blob: ee03c3f2052693cf2e5f0a10a0b6b6fe804d9d66 [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;
Eric Mooree80b0022007-09-14 18:49:03 -0600849 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600850
851 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
852 if (!vtarget)
853 return -ENOMEM;
854
855 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -0600856 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700857 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
858 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600859 channel = 0;
860
Eric Moore793955f2007-01-29 09:42:20 -0700861 /*
862 * RAID volumes placed beyond the last expected port.
863 */
864 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -0600865 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
866 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
867 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600868 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700869 }
Eric Moore547f9a22006-06-27 14:42:12 -0600870
871 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600872 mutex_lock(&ioc->sas_topology_mutex);
873 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600874 for (i = 0; i < p->num_phys; i++) {
875 if (p->phy_info[i].attached.sas_address !=
876 rphy->identify.sas_address)
877 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700878 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600879 channel = p->phy_info[i].attached.channel;
880 mptsas_set_starget(&p->phy_info[i], starget);
881
882 /*
883 * Exposing hidden raid components
884 */
Eric Mooree80b0022007-09-14 18:49:03 -0600885 if (mptscsih_is_phys_disk(ioc, channel, id)) {
886 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700887 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600888 vtarget->tflags |=
889 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700890 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600891 }
Eric Mooree80b0022007-09-14 18:49:03 -0600892 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600893 goto out;
894 }
895 }
Eric Mooree80b0022007-09-14 18:49:03 -0600896 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600897
898 kfree(vtarget);
899 return -ENXIO;
900
901 out:
Eric Moore793955f2007-01-29 09:42:20 -0700902 vtarget->id = id;
903 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600904 starget->hostdata = vtarget;
905 return 0;
906}
907
908static void
909mptsas_target_destroy(struct scsi_target *starget)
910{
911 struct Scsi_Host *host = dev_to_shost(&starget->dev);
912 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
913 struct sas_rphy *rphy;
914 struct mptsas_portinfo *p;
915 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600916 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600917
918 if (!starget->hostdata)
919 return;
920
James Bottomleye8bf3942006-07-11 17:49:34 -0400921 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600922 goto out;
923
924 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600925 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600926 for (i = 0; i < p->num_phys; i++) {
927 if (p->phy_info[i].attached.sas_address !=
928 rphy->identify.sas_address)
929 continue;
930 mptsas_set_starget(&p->phy_info[i], NULL);
931 goto out;
932 }
933 }
934
935 out:
936 kfree(starget->hostdata);
937 starget->hostdata = NULL;
938}
939
940
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200941static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700942mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200943{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700944 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200945 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
946 struct sas_rphy *rphy;
947 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -0600948 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700949 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600950 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600951 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200952
Eric Moorea69de502007-09-14 18:48:19 -0600953 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
954 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -0600955 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -0600956 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200957 return -ENOMEM;
958 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700959 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -0600960 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200961
James Bottomleye8bf3942006-07-11 17:49:34 -0400962 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -0700963 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700964
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700965 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600966 mutex_lock(&ioc->sas_topology_mutex);
967 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200968 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600969 if (p->phy_info[i].attached.sas_address !=
970 rphy->identify.sas_address)
971 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600972 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -0600973 /*
974 * Exposing hidden raid components
975 */
Eric Mooree80b0022007-09-14 18:49:03 -0600976 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700977 p->phy_info[i].attached.channel,
978 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -0600979 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -0600980 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600981 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200982 }
983 }
Eric Mooree80b0022007-09-14 18:49:03 -0600984 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200985
Eric Moorea69de502007-09-14 18:48:19 -0600986 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100987 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200988
989 out:
Eric Moorea69de502007-09-14 18:48:19 -0600990 vdevice->vtarget->num_luns++;
991 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200992 return 0;
993}
994
Eric Moore547f9a22006-06-27 14:42:12 -0600995static int
996mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100997{
Eric Moorea69de502007-09-14 18:48:19 -0600998 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100999
Eric Moorea69de502007-09-14 18:48:19 -06001000 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001001 SCpnt->result = DID_NO_CONNECT << 16;
1002 done(SCpnt);
1003 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001004 }
Eric Moore547f9a22006-06-27 14:42:12 -06001005
Eric Moore793955f2007-01-29 09:42:20 -07001006// scsi_print_command(SCpnt);
1007
Eric Moore547f9a22006-06-27 14:42:12 -06001008 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001009}
1010
Eric Moore547f9a22006-06-27 14:42:12 -06001011
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001012static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001013 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001014 .proc_name = "mptsas",
1015 .proc_info = mptscsih_proc_info,
1016 .name = "MPT SPI Host",
1017 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001018 .queuecommand = mptsas_qcmd,
1019 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001020 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001021 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001022 .target_destroy = mptsas_target_destroy,
1023 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001024 .change_queue_depth = mptscsih_change_queue_depth,
1025 .eh_abort_handler = mptscsih_abort,
1026 .eh_device_reset_handler = mptscsih_dev_reset,
1027 .eh_bus_reset_handler = mptscsih_bus_reset,
1028 .eh_host_reset_handler = mptscsih_host_reset,
1029 .bios_param = mptscsih_bios_param,
1030 .can_queue = MPT_FC_CAN_QUEUE,
1031 .this_id = -1,
1032 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1033 .max_sectors = 8192,
1034 .cmd_per_lun = 7,
1035 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301036 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001037};
1038
Christoph Hellwigb5141122005-10-28 22:07:41 +02001039static int mptsas_get_linkerrors(struct sas_phy *phy)
1040{
1041 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1042 ConfigExtendedPageHeader_t hdr;
1043 CONFIGPARMS cfg;
1044 SasPhyPage1_t *buffer;
1045 dma_addr_t dma_handle;
1046 int error;
1047
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001048 /* FIXME: only have link errors on local phys */
1049 if (!scsi_is_sas_phy_local(phy))
1050 return -EINVAL;
1051
Christoph Hellwigb5141122005-10-28 22:07:41 +02001052 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1053 hdr.ExtPageLength = 0;
1054 hdr.PageNumber = 1 /* page number 1*/;
1055 hdr.Reserved1 = 0;
1056 hdr.Reserved2 = 0;
1057 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1058 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1059
1060 cfg.cfghdr.ehdr = &hdr;
1061 cfg.physAddr = -1;
1062 cfg.pageAddr = phy->identify.phy_identifier;
1063 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1064 cfg.dir = 0; /* read */
1065 cfg.timeout = 10;
1066
1067 error = mpt_config(ioc, &cfg);
1068 if (error)
1069 return error;
1070 if (!hdr.ExtPageLength)
1071 return -ENXIO;
1072
1073 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1074 &dma_handle);
1075 if (!buffer)
1076 return -ENOMEM;
1077
1078 cfg.physAddr = dma_handle;
1079 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1080
1081 error = mpt_config(ioc, &cfg);
1082 if (error)
1083 goto out_free_consistent;
1084
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301085 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001086
1087 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1088 phy->running_disparity_error_count =
1089 le32_to_cpu(buffer->RunningDisparityErrorCount);
1090 phy->loss_of_dword_sync_count =
1091 le32_to_cpu(buffer->LossDwordSynchCount);
1092 phy->phy_reset_problem_count =
1093 le32_to_cpu(buffer->PhyResetProblemCount);
1094
1095 out_free_consistent:
1096 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1097 buffer, dma_handle);
1098 return error;
1099}
1100
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001101static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1102 MPT_FRAME_HDR *reply)
1103{
1104 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1105 if (reply != NULL) {
1106 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1107 memcpy(ioc->sas_mgmt.reply, reply,
1108 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1109 }
1110 complete(&ioc->sas_mgmt.done);
1111 return 1;
1112}
1113
1114static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1115{
1116 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1117 SasIoUnitControlRequest_t *req;
1118 SasIoUnitControlReply_t *reply;
1119 MPT_FRAME_HDR *mf;
1120 MPIHeader_t *hdr;
1121 unsigned long timeleft;
1122 int error = -ERESTARTSYS;
1123
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001124 /* FIXME: fusion doesn't allow non-local phy reset */
1125 if (!scsi_is_sas_phy_local(phy))
1126 return -EINVAL;
1127
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001128 /* not implemented for expanders */
1129 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1130 return -ENXIO;
1131
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001132 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001133 goto out;
1134
1135 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1136 if (!mf) {
1137 error = -ENOMEM;
1138 goto out_unlock;
1139 }
1140
1141 hdr = (MPIHeader_t *) mf;
1142 req = (SasIoUnitControlRequest_t *)mf;
1143 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1144 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1145 req->MsgContext = hdr->MsgContext;
1146 req->Operation = hard_reset ?
1147 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1148 req->PhyNum = phy->identify.phy_identifier;
1149
1150 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1151
1152 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1153 10 * HZ);
1154 if (!timeleft) {
1155 /* On timeout reset the board */
1156 mpt_free_msg_frame(ioc, mf);
1157 mpt_HardResetHandler(ioc, CAN_SLEEP);
1158 error = -ETIMEDOUT;
1159 goto out_unlock;
1160 }
1161
1162 /* a reply frame is expected */
1163 if ((ioc->sas_mgmt.status &
1164 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1165 error = -ENXIO;
1166 goto out_unlock;
1167 }
1168
1169 /* process the completed Reply Message Frame */
1170 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1171 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001172 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1173 ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001174 error = -ENXIO;
1175 goto out_unlock;
1176 }
1177
1178 error = 0;
1179
1180 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001181 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001182 out:
1183 return error;
1184}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001185
Christoph Hellwige3094442006-02-16 13:25:36 +01001186static int
1187mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1188{
1189 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1190 int i, error;
1191 struct mptsas_portinfo *p;
1192 struct mptsas_enclosure enclosure_info;
1193 u64 enclosure_handle;
1194
1195 mutex_lock(&ioc->sas_topology_mutex);
1196 list_for_each_entry(p, &ioc->sas_topology, list) {
1197 for (i = 0; i < p->num_phys; i++) {
1198 if (p->phy_info[i].attached.sas_address ==
1199 rphy->identify.sas_address) {
1200 enclosure_handle = p->phy_info[i].
1201 attached.handle_enclosure;
1202 goto found_info;
1203 }
1204 }
1205 }
1206 mutex_unlock(&ioc->sas_topology_mutex);
1207 return -ENXIO;
1208
1209 found_info:
1210 mutex_unlock(&ioc->sas_topology_mutex);
1211 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001212 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001213 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1214 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1215 if (!error)
1216 *identifier = enclosure_info.enclosure_logical_id;
1217 return error;
1218}
1219
1220static int
1221mptsas_get_bay_identifier(struct sas_rphy *rphy)
1222{
1223 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1224 struct mptsas_portinfo *p;
1225 int i, rc;
1226
1227 mutex_lock(&ioc->sas_topology_mutex);
1228 list_for_each_entry(p, &ioc->sas_topology, list) {
1229 for (i = 0; i < p->num_phys; i++) {
1230 if (p->phy_info[i].attached.sas_address ==
1231 rphy->identify.sas_address) {
1232 rc = p->phy_info[i].attached.slot;
1233 goto out;
1234 }
1235 }
1236 }
1237 rc = -ENXIO;
1238 out:
1239 mutex_unlock(&ioc->sas_topology_mutex);
1240 return rc;
1241}
1242
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001243static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1244 struct request *req)
1245{
1246 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1247 MPT_FRAME_HDR *mf;
1248 SmpPassthroughRequest_t *smpreq;
1249 struct request *rsp = req->next_rq;
1250 int ret;
1251 int flagsLength;
1252 unsigned long timeleft;
1253 char *psge;
1254 dma_addr_t dma_addr_in = 0;
1255 dma_addr_t dma_addr_out = 0;
1256 u64 sas_address = 0;
1257
1258 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001259 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
1260 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001261 return -EINVAL;
1262 }
1263
1264 /* do we need to support multiple segments? */
1265 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001266 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
1267 ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1268 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001269 return -EINVAL;
1270 }
1271
1272 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1273 if (ret)
1274 goto out;
1275
1276 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1277 if (!mf) {
1278 ret = -ENOMEM;
1279 goto out_unlock;
1280 }
1281
1282 smpreq = (SmpPassthroughRequest_t *)mf;
1283 memset(smpreq, 0, sizeof(*smpreq));
1284
1285 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1286 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1287
1288 if (rphy)
1289 sas_address = rphy->identify.sas_address;
1290 else {
1291 struct mptsas_portinfo *port_info;
1292
1293 mutex_lock(&ioc->sas_topology_mutex);
1294 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1295 if (port_info && port_info->phy_info)
1296 sas_address =
1297 port_info->phy_info[0].phy->identify.sas_address;
1298 mutex_unlock(&ioc->sas_topology_mutex);
1299 }
1300
1301 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1302
1303 psge = (char *)
1304 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1305
1306 /* request */
1307 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1308 MPI_SGE_FLAGS_END_OF_BUFFER |
1309 MPI_SGE_FLAGS_DIRECTION |
1310 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1311 flagsLength |= (req->data_len - 4);
1312
1313 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1314 req->data_len, PCI_DMA_BIDIRECTIONAL);
1315 if (!dma_addr_out)
1316 goto put_mf;
1317 mpt_add_sge(psge, flagsLength, dma_addr_out);
1318 psge += (sizeof(u32) + sizeof(dma_addr_t));
1319
1320 /* response */
1321 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1322 flagsLength |= rsp->data_len + 4;
1323 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1324 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1325 if (!dma_addr_in)
1326 goto unmap;
1327 mpt_add_sge(psge, flagsLength, dma_addr_in);
1328
1329 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1330
1331 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1332 if (!timeleft) {
Eric Moore29dd3602007-09-14 18:46:51 -06001333 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001334 /* On timeout reset the board */
1335 mpt_HardResetHandler(ioc, CAN_SLEEP);
1336 ret = -ETIMEDOUT;
1337 goto unmap;
1338 }
1339 mf = NULL;
1340
1341 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1342 SmpPassthroughReply_t *smprep;
1343
1344 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1345 memcpy(req->sense, smprep, sizeof(*smprep));
1346 req->sense_len = sizeof(*smprep);
1347 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001348 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
1349 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001350 ret = -ENXIO;
1351 }
1352unmap:
1353 if (dma_addr_out)
1354 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1355 PCI_DMA_BIDIRECTIONAL);
1356 if (dma_addr_in)
1357 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1358 PCI_DMA_BIDIRECTIONAL);
1359put_mf:
1360 if (mf)
1361 mpt_free_msg_frame(ioc, mf);
1362out_unlock:
1363 mutex_unlock(&ioc->sas_mgmt.mutex);
1364out:
1365 return ret;
1366}
1367
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001368static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001369 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001370 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1371 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001372 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001373 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001374};
1375
1376static struct scsi_transport_template *mptsas_transport_template;
1377
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001378static int
1379mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1380{
1381 ConfigExtendedPageHeader_t hdr;
1382 CONFIGPARMS cfg;
1383 SasIOUnitPage0_t *buffer;
1384 dma_addr_t dma_handle;
1385 int error, i;
1386
1387 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1388 hdr.ExtPageLength = 0;
1389 hdr.PageNumber = 0;
1390 hdr.Reserved1 = 0;
1391 hdr.Reserved2 = 0;
1392 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1393 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1394
1395 cfg.cfghdr.ehdr = &hdr;
1396 cfg.physAddr = -1;
1397 cfg.pageAddr = 0;
1398 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1399 cfg.dir = 0; /* read */
1400 cfg.timeout = 10;
1401
1402 error = mpt_config(ioc, &cfg);
1403 if (error)
1404 goto out;
1405 if (!hdr.ExtPageLength) {
1406 error = -ENXIO;
1407 goto out;
1408 }
1409
1410 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1411 &dma_handle);
1412 if (!buffer) {
1413 error = -ENOMEM;
1414 goto out;
1415 }
1416
1417 cfg.physAddr = dma_handle;
1418 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1419
1420 error = mpt_config(ioc, &cfg);
1421 if (error)
1422 goto out_free_consistent;
1423
1424 port_info->num_phys = buffer->NumPhys;
1425 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001426 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001427 if (!port_info->phy_info) {
1428 error = -ENOMEM;
1429 goto out_free_consistent;
1430 }
1431
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301432 ioc->nvdata_version_persistent =
1433 le16_to_cpu(buffer->NvdataVersionPersistent);
1434 ioc->nvdata_version_default =
1435 le16_to_cpu(buffer->NvdataVersionDefault);
1436
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001437 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301438 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001439 port_info->phy_info[i].phy_id = i;
1440 port_info->phy_info[i].port_id =
1441 buffer->PhyData[i].Port;
1442 port_info->phy_info[i].negotiated_link_rate =
1443 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001444 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001445 port_info->phy_info[i].handle =
1446 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001447 }
1448
1449 out_free_consistent:
1450 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1451 buffer, dma_handle);
1452 out:
1453 return error;
1454}
1455
1456static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301457mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1458{
1459 ConfigExtendedPageHeader_t hdr;
1460 CONFIGPARMS cfg;
1461 SasIOUnitPage1_t *buffer;
1462 dma_addr_t dma_handle;
1463 int error;
1464 u16 device_missing_delay;
1465
1466 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1467 memset(&cfg, 0, sizeof(CONFIGPARMS));
1468
1469 cfg.cfghdr.ehdr = &hdr;
1470 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1471 cfg.timeout = 10;
1472 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1473 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1474 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1475 cfg.cfghdr.ehdr->PageNumber = 1;
1476
1477 error = mpt_config(ioc, &cfg);
1478 if (error)
1479 goto out;
1480 if (!hdr.ExtPageLength) {
1481 error = -ENXIO;
1482 goto out;
1483 }
1484
1485 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1486 &dma_handle);
1487 if (!buffer) {
1488 error = -ENOMEM;
1489 goto out;
1490 }
1491
1492 cfg.physAddr = dma_handle;
1493 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1494
1495 error = mpt_config(ioc, &cfg);
1496 if (error)
1497 goto out_free_consistent;
1498
1499 ioc->io_missing_delay =
1500 le16_to_cpu(buffer->IODeviceMissingDelay);
1501 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1502 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1503 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1504 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1505
1506 out_free_consistent:
1507 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1508 buffer, dma_handle);
1509 out:
1510 return error;
1511}
1512
1513static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001514mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1515 u32 form, u32 form_specific)
1516{
1517 ConfigExtendedPageHeader_t hdr;
1518 CONFIGPARMS cfg;
1519 SasPhyPage0_t *buffer;
1520 dma_addr_t dma_handle;
1521 int error;
1522
1523 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1524 hdr.ExtPageLength = 0;
1525 hdr.PageNumber = 0;
1526 hdr.Reserved1 = 0;
1527 hdr.Reserved2 = 0;
1528 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1529 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1530
1531 cfg.cfghdr.ehdr = &hdr;
1532 cfg.dir = 0; /* read */
1533 cfg.timeout = 10;
1534
1535 /* Get Phy Pg 0 for each Phy. */
1536 cfg.physAddr = -1;
1537 cfg.pageAddr = form + form_specific;
1538 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1539
1540 error = mpt_config(ioc, &cfg);
1541 if (error)
1542 goto out;
1543
1544 if (!hdr.ExtPageLength) {
1545 error = -ENXIO;
1546 goto out;
1547 }
1548
1549 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1550 &dma_handle);
1551 if (!buffer) {
1552 error = -ENOMEM;
1553 goto out;
1554 }
1555
1556 cfg.physAddr = dma_handle;
1557 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1558
1559 error = mpt_config(ioc, &cfg);
1560 if (error)
1561 goto out_free_consistent;
1562
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301563 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001564
1565 phy_info->hw_link_rate = buffer->HwLinkRate;
1566 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1567 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1568 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1569
1570 out_free_consistent:
1571 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1572 buffer, dma_handle);
1573 out:
1574 return error;
1575}
1576
1577static int
1578mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1579 u32 form, u32 form_specific)
1580{
1581 ConfigExtendedPageHeader_t hdr;
1582 CONFIGPARMS cfg;
1583 SasDevicePage0_t *buffer;
1584 dma_addr_t dma_handle;
1585 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001586 int error=0;
1587
1588 if (ioc->sas_discovery_runtime &&
1589 mptsas_is_end_device(device_info))
1590 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001591
1592 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1593 hdr.ExtPageLength = 0;
1594 hdr.PageNumber = 0;
1595 hdr.Reserved1 = 0;
1596 hdr.Reserved2 = 0;
1597 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1598 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1599
1600 cfg.cfghdr.ehdr = &hdr;
1601 cfg.pageAddr = form + form_specific;
1602 cfg.physAddr = -1;
1603 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1604 cfg.dir = 0; /* read */
1605 cfg.timeout = 10;
1606
Moore, Ericdb9c9172006-03-14 09:14:18 -07001607 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001608 error = mpt_config(ioc, &cfg);
1609 if (error)
1610 goto out;
1611 if (!hdr.ExtPageLength) {
1612 error = -ENXIO;
1613 goto out;
1614 }
1615
1616 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1617 &dma_handle);
1618 if (!buffer) {
1619 error = -ENOMEM;
1620 goto out;
1621 }
1622
1623 cfg.physAddr = dma_handle;
1624 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1625
1626 error = mpt_config(ioc, &cfg);
1627 if (error)
1628 goto out_free_consistent;
1629
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301630 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001631
1632 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07001633 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001634 device_info->handle_enclosure =
1635 le16_to_cpu(buffer->EnclosureHandle);
1636 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001637 device_info->phy_id = buffer->PhyNum;
1638 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001639 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001640 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001641 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001642 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1643 device_info->sas_address = le64_to_cpu(sas_address);
1644 device_info->device_info =
1645 le32_to_cpu(buffer->DeviceInfo);
1646
1647 out_free_consistent:
1648 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1649 buffer, dma_handle);
1650 out:
1651 return error;
1652}
1653
1654static int
1655mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1656 u32 form, u32 form_specific)
1657{
1658 ConfigExtendedPageHeader_t hdr;
1659 CONFIGPARMS cfg;
1660 SasExpanderPage0_t *buffer;
1661 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001662 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001663
1664 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1665 hdr.ExtPageLength = 0;
1666 hdr.PageNumber = 0;
1667 hdr.Reserved1 = 0;
1668 hdr.Reserved2 = 0;
1669 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1670 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1671
1672 cfg.cfghdr.ehdr = &hdr;
1673 cfg.physAddr = -1;
1674 cfg.pageAddr = form + form_specific;
1675 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1676 cfg.dir = 0; /* read */
1677 cfg.timeout = 10;
1678
Moore, Ericdb9c9172006-03-14 09:14:18 -07001679 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001680 error = mpt_config(ioc, &cfg);
1681 if (error)
1682 goto out;
1683
1684 if (!hdr.ExtPageLength) {
1685 error = -ENXIO;
1686 goto out;
1687 }
1688
1689 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1690 &dma_handle);
1691 if (!buffer) {
1692 error = -ENOMEM;
1693 goto out;
1694 }
1695
1696 cfg.physAddr = dma_handle;
1697 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1698
1699 error = mpt_config(ioc, &cfg);
1700 if (error)
1701 goto out_free_consistent;
1702
1703 /* save config data */
1704 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001705 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001706 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001707 if (!port_info->phy_info) {
1708 error = -ENOMEM;
1709 goto out_free_consistent;
1710 }
1711
Eric Moore2ecce492007-01-29 09:47:08 -07001712 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001713 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001714 port_info->phy_info[i].handle =
1715 le16_to_cpu(buffer->DevHandle);
1716 }
Eric Moore547f9a22006-06-27 14:42:12 -06001717
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001718 out_free_consistent:
1719 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1720 buffer, dma_handle);
1721 out:
1722 return error;
1723}
1724
1725static int
1726mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1727 u32 form, u32 form_specific)
1728{
1729 ConfigExtendedPageHeader_t hdr;
1730 CONFIGPARMS cfg;
1731 SasExpanderPage1_t *buffer;
1732 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001733 int error=0;
1734
1735 if (ioc->sas_discovery_runtime &&
1736 mptsas_is_end_device(&phy_info->attached))
1737 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001738
1739 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1740 hdr.ExtPageLength = 0;
1741 hdr.PageNumber = 1;
1742 hdr.Reserved1 = 0;
1743 hdr.Reserved2 = 0;
1744 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1745 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1746
1747 cfg.cfghdr.ehdr = &hdr;
1748 cfg.physAddr = -1;
1749 cfg.pageAddr = form + form_specific;
1750 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1751 cfg.dir = 0; /* read */
1752 cfg.timeout = 10;
1753
1754 error = mpt_config(ioc, &cfg);
1755 if (error)
1756 goto out;
1757
1758 if (!hdr.ExtPageLength) {
1759 error = -ENXIO;
1760 goto out;
1761 }
1762
1763 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1764 &dma_handle);
1765 if (!buffer) {
1766 error = -ENOMEM;
1767 goto out;
1768 }
1769
1770 cfg.physAddr = dma_handle;
1771 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1772
1773 error = mpt_config(ioc, &cfg);
1774 if (error)
1775 goto out_free_consistent;
1776
1777
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301778 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001779
1780 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001781 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001782 phy_info->port_id = buffer->PhysicalPort;
1783 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1784 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1785 phy_info->hw_link_rate = buffer->HwLinkRate;
1786 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1787 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1788
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001789 out_free_consistent:
1790 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1791 buffer, dma_handle);
1792 out:
1793 return error;
1794}
1795
1796static void
1797mptsas_parse_device_info(struct sas_identify *identify,
1798 struct mptsas_devinfo *device_info)
1799{
1800 u16 protocols;
1801
1802 identify->sas_address = device_info->sas_address;
1803 identify->phy_identifier = device_info->phy_id;
1804
1805 /*
1806 * Fill in Phy Initiator Port Protocol.
1807 * Bits 6:3, more than one bit can be set, fall through cases.
1808 */
1809 protocols = device_info->device_info & 0x78;
1810 identify->initiator_port_protocols = 0;
1811 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1812 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1813 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1814 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1815 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1816 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1817 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1818 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1819
1820 /*
1821 * Fill in Phy Target Port Protocol.
1822 * Bits 10:7, more than one bit can be set, fall through cases.
1823 */
1824 protocols = device_info->device_info & 0x780;
1825 identify->target_port_protocols = 0;
1826 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1827 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1828 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1829 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1830 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1831 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1832 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1833 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1834
1835 /*
1836 * Fill in Attached device type.
1837 */
1838 switch (device_info->device_info &
1839 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1840 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1841 identify->device_type = SAS_PHY_UNUSED;
1842 break;
1843 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1844 identify->device_type = SAS_END_DEVICE;
1845 break;
1846 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1847 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1848 break;
1849 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1850 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1851 break;
1852 }
1853}
1854
1855static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001856 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857{
Moore, Erice6b2d762006-03-14 09:14:24 -07001858 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001859 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001860 struct sas_port *port;
1861 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001862
Eric Moore547f9a22006-06-27 14:42:12 -06001863 if (!dev) {
1864 error = -ENODEV;
1865 goto out;
1866 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001867
1868 if (!phy_info->phy) {
1869 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001870 if (!phy) {
1871 error = -ENOMEM;
1872 goto out;
1873 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001874 } else
1875 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001876
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001877 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001878
1879 /*
1880 * Set Negotiated link rate.
1881 */
1882 switch (phy_info->negotiated_link_rate) {
1883 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001884 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 break;
1886 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001887 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 break;
1889 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001891 break;
1892 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001893 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001894 break;
1895 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1896 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1897 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001898 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001899 break;
1900 }
1901
1902 /*
1903 * Set Max hardware link rate.
1904 */
1905 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1906 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001907 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001908 break;
1909 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001910 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001911 break;
1912 default:
1913 break;
1914 }
1915
1916 /*
1917 * Set Max programmed link rate.
1918 */
1919 switch (phy_info->programmed_link_rate &
1920 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1921 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001922 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001923 break;
1924 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001925 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001926 break;
1927 default:
1928 break;
1929 }
1930
1931 /*
1932 * Set Min hardware link rate.
1933 */
1934 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1935 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001936 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001937 break;
1938 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001939 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001940 break;
1941 default:
1942 break;
1943 }
1944
1945 /*
1946 * Set Min programmed link rate.
1947 */
1948 switch (phy_info->programmed_link_rate &
1949 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1950 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001951 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001952 break;
1953 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001954 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001955 break;
1956 default:
1957 break;
1958 }
1959
Moore, Erice6b2d762006-03-14 09:14:24 -07001960 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001961
Moore, Erice6b2d762006-03-14 09:14:24 -07001962 error = sas_phy_add(phy);
1963 if (error) {
1964 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001965 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001966 }
1967 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001968 }
1969
Eric Moore547f9a22006-06-27 14:42:12 -06001970 if (!phy_info->attached.handle ||
1971 !phy_info->port_details)
1972 goto out;
1973
1974 port = mptsas_get_port(phy_info);
1975 ioc = phy_to_ioc(phy_info->phy);
1976
1977 if (phy_info->sas_port_add_phy) {
1978
1979 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001980 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001981 if (!port) {
1982 error = -ENOMEM;
1983 goto out;
1984 }
1985 error = sas_port_add(port);
1986 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301987 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001988 "%s: exit at line=%d\n", ioc->name,
1989 __FUNCTION__, __LINE__));
1990 goto out;
1991 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301992 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06001993 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06001994 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001995 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001996 }
Eric Moore29dd3602007-09-14 18:46:51 -06001997 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
1998 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06001999 sas_port_add_phy(port, phy_info->phy);
2000 phy_info->sas_port_add_phy = 0;
2001 }
2002
2003 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002004
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002005 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002006 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002007 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002008
James Bottomley2686de22006-06-30 12:54:02 -05002009 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002010 /*
2011 * Let the hotplug_work thread handle processing
2012 * the adding/removing of devices that occur
2013 * after start of day.
2014 */
2015 if (ioc->sas_discovery_runtime &&
2016 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002017 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002018
James Bottomleyf013db32006-03-18 14:54:36 -06002019 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002020 if (scsi_is_host_device(parent)) {
2021 struct mptsas_portinfo *port_info;
2022 int i;
2023
2024 mutex_lock(&ioc->sas_topology_mutex);
2025 port_info = mptsas_find_portinfo_by_handle(ioc,
2026 ioc->handle);
2027 mutex_unlock(&ioc->sas_topology_mutex);
2028
2029 for (i = 0; i < port_info->num_phys; i++)
2030 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002031 identify.sas_address) {
2032 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002033 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002034 }
James Bottomley2686de22006-06-30 12:54:02 -05002035
2036 } else if (scsi_is_sas_rphy(parent)) {
2037 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2038 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002039 parent_rphy->identify.sas_address) {
2040 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002041 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002042 }
James Bottomley2686de22006-06-30 12:54:02 -05002043 }
2044
James Bottomleyf013db32006-03-18 14:54:36 -06002045 switch (identify.device_type) {
2046 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002047 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002048 break;
2049 case SAS_EDGE_EXPANDER_DEVICE:
2050 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002051 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002052 break;
2053 default:
2054 rphy = NULL;
2055 break;
2056 }
Eric Moore547f9a22006-06-27 14:42:12 -06002057 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302058 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002059 "%s: exit at line=%d\n", ioc->name,
2060 __FUNCTION__, __LINE__));
2061 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002062 }
2063
Eric Moore547f9a22006-06-27 14:42:12 -06002064 rphy->identify = identify;
2065 error = sas_rphy_add(rphy);
2066 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302067 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002068 "%s: exit at line=%d\n", ioc->name,
2069 __FUNCTION__, __LINE__));
2070 sas_rphy_free(rphy);
2071 goto out;
2072 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302073 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002074 }
2075
Eric Moore547f9a22006-06-27 14:42:12 -06002076 out:
2077 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002078}
2079
2080static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002081mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002082{
Moore, Erice6b2d762006-03-14 09:14:24 -07002083 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002084 int error = -ENOMEM, i;
2085
Moore, Erice6b2d762006-03-14 09:14:24 -07002086 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2087 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002088 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002089
Moore, Erice6b2d762006-03-14 09:14:24 -07002090 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002091 if (error)
2092 goto out_free_port_info;
2093
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302094 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002095 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002096 ioc->handle = hba->phy_info[0].handle;
2097 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002098 if (!port_info) {
2099 port_info = hba;
2100 list_add_tail(&port_info->list, &ioc->sas_topology);
2101 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002102 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002103 port_info->phy_info[i].negotiated_link_rate =
2104 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002105 port_info->phy_info[i].handle =
2106 hba->phy_info[i].handle;
2107 port_info->phy_info[i].port_id =
2108 hba->phy_info[i].port_id;
2109 }
Eric Moore547f9a22006-06-27 14:42:12 -06002110 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002111 kfree(hba);
2112 hba = NULL;
2113 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002114 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002115 for (i = 0; i < port_info->num_phys; i++) {
2116 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2117 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2118 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2119
2120 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002121 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2122 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2123 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002124 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002125 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002126 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002127 mptsas_sas_device_pg0(ioc,
2128 &port_info->phy_info[i].attached,
2129 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2130 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2131 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002132 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002133
Eric Moore547f9a22006-06-27 14:42:12 -06002134 mptsas_setup_wide_ports(ioc, port_info);
2135
2136 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002137 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002138 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002139
2140 return 0;
2141
2142 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002143 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002144 out:
2145 return error;
2146}
2147
2148static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002149mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002150{
Moore, Erice6b2d762006-03-14 09:14:24 -07002151 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002152 struct device *parent;
2153 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002154 int error = -ENOMEM, i, j;
2155
Moore, Erice6b2d762006-03-14 09:14:24 -07002156 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2157 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002158 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002159
Moore, Erice6b2d762006-03-14 09:14:24 -07002160 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002161 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2162 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002163 if (error)
2164 goto out_free_port_info;
2165
Eric Moore2ecce492007-01-29 09:47:08 -07002166 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002167
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002168 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002169 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2170 if (!port_info) {
2171 port_info = ex;
2172 list_add_tail(&port_info->list, &ioc->sas_topology);
2173 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002174 for (i = 0; i < ex->num_phys; i++) {
2175 port_info->phy_info[i].handle =
2176 ex->phy_info[i].handle;
2177 port_info->phy_info[i].port_id =
2178 ex->phy_info[i].port_id;
2179 }
Eric Moore547f9a22006-06-27 14:42:12 -06002180 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002181 kfree(ex);
2182 ex = NULL;
2183 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002184 mutex_unlock(&ioc->sas_topology_mutex);
2185
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002186 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002187 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2188 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2189 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2190
2191 if (port_info->phy_info[i].identify.handle) {
2192 mptsas_sas_device_pg0(ioc,
2193 &port_info->phy_info[i].identify,
2194 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2195 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2196 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002197 port_info->phy_info[i].identify.phy_id =
2198 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002199 }
2200
2201 if (port_info->phy_info[i].attached.handle) {
2202 mptsas_sas_device_pg0(ioc,
2203 &port_info->phy_info[i].attached,
2204 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2205 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2206 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002207 port_info->phy_info[i].attached.phy_id =
2208 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002209 }
Eric Moore547f9a22006-06-27 14:42:12 -06002210 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002211
Eric Moore547f9a22006-06-27 14:42:12 -06002212 parent = &ioc->sh->shost_gendev;
2213 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002214 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002215 list_for_each_entry(p, &ioc->sas_topology, list) {
2216 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002217 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002218 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002219 continue;
2220 rphy = mptsas_get_rphy(&p->phy_info[j]);
2221 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002222 }
2223 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002224 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002225 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002226
Eric Moore547f9a22006-06-27 14:42:12 -06002227 mptsas_setup_wide_ports(ioc, port_info);
2228
2229 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002230 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002231 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002232
2233 return 0;
2234
2235 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002236 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002237 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002238 kfree(ex);
2239 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002240 out:
2241 return error;
2242}
2243
Moore, Erice6b2d762006-03-14 09:14:24 -07002244/*
2245 * mptsas_delete_expander_phys
2246 *
2247 *
2248 * This will traverse topology, and remove expanders
2249 * that are no longer present
2250 */
2251static void
2252mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2253{
2254 struct mptsas_portinfo buffer;
2255 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002256 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002257 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002258 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002259 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002260
2261 mutex_lock(&ioc->sas_topology_mutex);
2262 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2263
2264 if (port_info->phy_info &&
2265 (!(port_info->phy_info[0].identify.device_info &
2266 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2267 continue;
2268
2269 if (mptsas_sas_expander_pg0(ioc, &buffer,
2270 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002271 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2272 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002273
2274 /*
2275 * Obtain the port_info instance to the parent port
2276 */
2277 parent = mptsas_find_portinfo_by_handle(ioc,
2278 port_info->phy_info[0].identify.handle_parent);
2279
2280 if (!parent)
2281 goto next_port;
2282
Eric Moore547f9a22006-06-27 14:42:12 -06002283 expander_sas_address =
2284 port_info->phy_info[0].identify.sas_address;
2285
Moore, Erice6b2d762006-03-14 09:14:24 -07002286 /*
2287 * Delete rphys in the parent that point
2288 * to this expander. The transport layer will
2289 * cleanup all the children.
2290 */
Eric Moore547f9a22006-06-27 14:42:12 -06002291 phy_info = parent->phy_info;
2292 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2293 port = mptsas_get_port(phy_info);
2294 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002295 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002296 if (phy_info->attached.sas_address !=
2297 expander_sas_address)
2298 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302299 dsaswideprintk(ioc,
Eric Moore29dd3602007-09-14 18:46:51 -06002300 dev_printk(MYIOC_s_DEBUG_FMT, &port->dev,
2301 "delete port (%d)\n", ioc->name, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002302 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302303 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002304 }
2305 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002306
2307 phy_info = port_info->phy_info;
2308 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302309 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002310
Moore, Erice6b2d762006-03-14 09:14:24 -07002311 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002312 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002313 kfree(port_info);
2314 }
2315 /*
2316 * Free this memory allocated from inside
2317 * mptsas_sas_expander_pg0
2318 */
Eric Moore547f9a22006-06-27 14:42:12 -06002319 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002320 }
2321 mutex_unlock(&ioc->sas_topology_mutex);
2322}
2323
2324/*
2325 * Start of day discovery
2326 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002327static void
2328mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2329{
2330 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002331 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002332
Moore, Erice6b2d762006-03-14 09:14:24 -07002333 mutex_lock(&ioc->sas_discovery_mutex);
2334 mptsas_probe_hba_phys(ioc);
2335 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002336 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002337 /*
2338 Reporting RAID volumes.
2339 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002340 if (!ioc->ir_firmware)
2341 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002342 if (!ioc->raid_data.pIocPg2)
2343 goto out;
2344 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2345 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002346 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002347 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002348 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2349 }
2350 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002351 mutex_unlock(&ioc->sas_discovery_mutex);
2352}
2353
2354/*
2355 * Work queue thread to handle Runtime discovery
2356 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002357 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002358 */
2359static void
Eric Moore547f9a22006-06-27 14:42:12 -06002360__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002361{
Moore, Erice6b2d762006-03-14 09:14:24 -07002362 u32 handle = 0xFFFF;
2363
Moore, Erice6b2d762006-03-14 09:14:24 -07002364 ioc->sas_discovery_runtime=1;
2365 mptsas_delete_expander_phys(ioc);
2366 mptsas_probe_hba_phys(ioc);
2367 while (!mptsas_probe_expander_phys(ioc, &handle))
2368 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002369 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002370}
2371
2372/*
2373 * Work queue thread to handle Runtime discovery
2374 * Mere purpose is the hot add/delete of expanders
2375 *(Mutex LOCKED)
2376 */
2377static void
David Howellsc4028952006-11-22 14:57:56 +00002378mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002379{
David Howellsc4028952006-11-22 14:57:56 +00002380 struct mptsas_discovery_event *ev =
2381 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002382 MPT_ADAPTER *ioc = ev->ioc;
2383
2384 mutex_lock(&ioc->sas_discovery_mutex);
2385 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002386 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002387 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002388}
2389
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002390static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002391mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002392{
2393 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002394 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002395 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002396
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002397 mutex_lock(&ioc->sas_topology_mutex);
2398 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2399 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002400 if (!mptsas_is_end_device(
2401 &port_info->phy_info[i].attached))
2402 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002403 if (port_info->phy_info[i].attached.sas_address
2404 != sas_address)
2405 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002406 phy_info = &port_info->phy_info[i];
2407 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002408 }
2409 }
2410 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002411 return phy_info;
2412}
2413
2414static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002415mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002416{
2417 struct mptsas_portinfo *port_info;
2418 struct mptsas_phyinfo *phy_info = NULL;
2419 int i;
2420
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002421 mutex_lock(&ioc->sas_topology_mutex);
2422 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002423 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002424 if (!mptsas_is_end_device(
2425 &port_info->phy_info[i].attached))
2426 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002427 if (port_info->phy_info[i].attached.id != id)
2428 continue;
2429 if (port_info->phy_info[i].attached.channel != channel)
2430 continue;
2431 phy_info = &port_info->phy_info[i];
2432 break;
2433 }
2434 }
2435 mutex_unlock(&ioc->sas_topology_mutex);
2436 return phy_info;
2437}
2438
2439static struct mptsas_phyinfo *
2440mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2441{
2442 struct mptsas_portinfo *port_info;
2443 struct mptsas_phyinfo *phy_info = NULL;
2444 int i;
2445
2446 mutex_lock(&ioc->sas_topology_mutex);
2447 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2448 for (i = 0; i < port_info->num_phys; i++) {
2449 if (!mptsas_is_end_device(
2450 &port_info->phy_info[i].attached))
2451 continue;
2452 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2453 continue;
2454 if (port_info->phy_info[i].attached.phys_disk_num != id)
2455 continue;
2456 if (port_info->phy_info[i].attached.channel != channel)
2457 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002458 phy_info = &port_info->phy_info[i];
2459 break;
2460 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002461 }
2462 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002463 return phy_info;
2464}
2465
Moore, Eric4b766472006-03-14 09:14:12 -07002466/*
2467 * Work queue thread to clear the persitency table
2468 */
2469static void
David Howellsc4028952006-11-22 14:57:56 +00002470mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002471{
David Howellsc4028952006-11-22 14:57:56 +00002472 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002473
2474 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2475}
2476
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002477static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002478mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2479{
Eric Mooref99be432007-01-04 20:46:54 -07002480 int rc;
2481
Moore, Ericf44e5462006-03-14 09:14:21 -07002482 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002483 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002484}
2485
2486static void
2487mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2488{
2489 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2490 mptsas_reprobe_lun);
2491}
2492
Eric Mooreb506ade2007-01-29 09:45:37 -07002493static void
2494mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2495{
2496 CONFIGPARMS cfg;
2497 ConfigPageHeader_t hdr;
2498 dma_addr_t dma_handle;
2499 pRaidVolumePage0_t buffer = NULL;
2500 RaidPhysDiskPage0_t phys_disk;
2501 int i;
2502 struct mptsas_hotplug_event *ev;
2503
2504 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2505 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2506 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2507 cfg.pageAddr = (channel << 8) + id;
2508 cfg.cfghdr.hdr = &hdr;
2509 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2510
2511 if (mpt_config(ioc, &cfg) != 0)
2512 goto out;
2513
2514 if (!hdr.PageLength)
2515 goto out;
2516
2517 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2518 &dma_handle);
2519
2520 if (!buffer)
2521 goto out;
2522
2523 cfg.physAddr = dma_handle;
2524 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2525
2526 if (mpt_config(ioc, &cfg) != 0)
2527 goto out;
2528
2529 if (!(buffer->VolumeStatus.Flags &
2530 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2531 goto out;
2532
2533 if (!buffer->NumPhysDisks)
2534 goto out;
2535
2536 for (i = 0; i < buffer->NumPhysDisks; i++) {
2537
2538 if (mpt_raid_phys_disk_pg0(ioc,
2539 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2540 continue;
2541
2542 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2543 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002544 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002545 goto out;
2546 }
2547
2548 INIT_WORK(&ev->work, mptsas_hotplug_work);
2549 ev->ioc = ioc;
2550 ev->id = phys_disk.PhysDiskID;
2551 ev->channel = phys_disk.PhysDiskBus;
2552 ev->phys_disk_num_valid = 1;
2553 ev->phys_disk_num = phys_disk.PhysDiskNum;
2554 ev->event_type = MPTSAS_ADD_DEVICE;
2555 schedule_work(&ev->work);
2556 }
2557
2558 out:
2559 if (buffer)
2560 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2561 dma_handle);
2562}
Moore, Erice6b2d762006-03-14 09:14:24 -07002563/*
2564 * Work queue thread to handle SAS hotplug events
2565 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002566static void
David Howellsc4028952006-11-22 14:57:56 +00002567mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002568{
David Howellsc4028952006-11-22 14:57:56 +00002569 struct mptsas_hotplug_event *ev =
2570 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002571
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002572 MPT_ADAPTER *ioc = ev->ioc;
2573 struct mptsas_phyinfo *phy_info;
2574 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002575 struct sas_port *port;
Moore, Ericc73787e2006-01-26 16:20:06 -07002576 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002577 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002578 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002579 char *ds = NULL;
Moore, Ericc73787e2006-01-26 16:20:06 -07002580 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002581 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002582 VirtDevice *vdevice;
2583
Moore, Erice6b2d762006-03-14 09:14:24 -07002584 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002585 switch (ev->event_type) {
2586 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002587
Eric Mooreb506ade2007-01-29 09:45:37 -07002588 phy_info = NULL;
2589 if (ev->phys_disk_num_valid) {
2590 if (ev->hidden_raid_component){
2591 if (mptsas_sas_device_pg0(ioc, &sas_device,
2592 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2593 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2594 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302595 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002596 "%s: exit at line=%d\n", ioc->name,
2597 __FUNCTION__, __LINE__));
2598 break;
2599 }
2600 phy_info = mptsas_find_phyinfo_by_sas_address(
2601 ioc, sas_device.sas_address);
2602 }else
2603 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2604 ioc, ev->channel, ev->phys_disk_num);
2605 }
2606
2607 if (!phy_info)
2608 phy_info = mptsas_find_phyinfo_by_target(ioc,
2609 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002610
Moore, Ericf44e5462006-03-14 09:14:21 -07002611 /*
2612 * Sanity checks, for non-existing phys and remote rphys.
2613 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002614 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302615 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002616 "%s: exit at line=%d\n", ioc->name,
2617 __FUNCTION__, __LINE__));
2618 break;
2619 }
2620 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302621 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002622 "%s: exit at line=%d\n", ioc->name,
2623 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002624 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002625 }
2626 rphy = mptsas_get_rphy(phy_info);
2627 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302628 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002629 "%s: exit at line=%d\n", ioc->name,
2630 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002631 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002632 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002633
Eric Moore547f9a22006-06-27 14:42:12 -06002634 port = mptsas_get_port(phy_info);
2635 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302636 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002637 "%s: exit at line=%d\n", ioc->name,
2638 __FUNCTION__, __LINE__));
2639 break;
2640 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002641
Eric Moore547f9a22006-06-27 14:42:12 -06002642 starget = mptsas_get_starget(phy_info);
2643 if (starget) {
2644 vtarget = starget->hostdata;
2645
2646 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302647 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002648 "%s: exit at line=%d\n", ioc->name,
2649 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002650 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002651 }
2652
Moore, Ericf44e5462006-03-14 09:14:21 -07002653 /*
2654 * Handling RAID components
2655 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002656 if (ev->phys_disk_num_valid &&
2657 ev->hidden_raid_component) {
2658 printk(MYIOC_s_INFO_FMT
2659 "RAID Hidding: channel=%d, id=%d, "
2660 "physdsk %d \n", ioc->name, ev->channel,
2661 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002662 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002663 vtarget->tflags |=
2664 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002665 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002666 phy_info->attached.phys_disk_num =
2667 ev->phys_disk_num;
2668 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002669 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002670 }
2671
Eric Mooreb506ade2007-01-29 09:45:37 -07002672 if (phy_info->attached.device_info &
2673 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787e2006-01-26 16:20:06 -07002674 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002675 if (phy_info->attached.device_info &
2676 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787e2006-01-26 16:20:06 -07002677 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002678 if (phy_info->attached.device_info &
2679 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787e2006-01-26 16:20:06 -07002680 ds = "sata";
2681
2682 printk(MYIOC_s_INFO_FMT
2683 "removing %s device, channel %d, id %d, phy %d\n",
2684 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore29dd3602007-09-14 18:46:51 -06002685 dev_printk(MYIOC_s_DEBUG_FMT, &port->dev,
2686 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002687 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302688 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002689 break;
2690 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787e2006-01-26 16:20:06 -07002691
Moore, Ericbd23e942006-04-17 12:43:04 -06002692 if (ev->phys_disk_num_valid)
2693 mpt_findImVolumes(ioc);
2694
Moore, Ericc73787e2006-01-26 16:20:06 -07002695 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002696 * Refresh sas device pg0 data
Moore, Ericc73787e2006-01-26 16:20:06 -07002697 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002698 if (mptsas_sas_device_pg0(ioc, &sas_device,
2699 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002700 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2701 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302702 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002703 "%s: exit at line=%d\n", ioc->name,
2704 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002705 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002706 }
2707
Eric Moore547f9a22006-06-27 14:42:12 -06002708 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002709
Eric Moore547f9a22006-06-27 14:42:12 -06002710 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2711 sas_device.sas_address);
2712
2713 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302714 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002715 "%s: exit at line=%d\n", ioc->name,
2716 __FUNCTION__, __LINE__));
2717 break;
2718 }
2719
2720 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002721 if (starget && (!ev->hidden_raid_component)){
2722
Eric Moore547f9a22006-06-27 14:42:12 -06002723 vtarget = starget->hostdata;
2724
2725 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302726 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002727 "%s: exit at line=%d\n", ioc->name,
2728 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002729 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002730 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002731 /*
2732 * Handling RAID components
2733 */
2734 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002735 printk(MYIOC_s_INFO_FMT
2736 "RAID Exposing: channel=%d, id=%d, "
2737 "physdsk %d \n", ioc->name, ev->channel,
2738 ev->id, ev->phys_disk_num);
2739 vtarget->tflags &=
2740 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002741 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002742 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002743 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002744 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002745 break;
2746 }
2747
Eric Moore547f9a22006-06-27 14:42:12 -06002748 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302749 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002750 "%s: exit at line=%d\n", ioc->name,
2751 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002752 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002753 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002754 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002755
Eric Moore547f9a22006-06-27 14:42:12 -06002756 port = mptsas_get_port(phy_info);
2757 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302758 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002759 "%s: exit at line=%d\n", ioc->name,
2760 __FUNCTION__, __LINE__));
2761 break;
2762 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002763 memcpy(&phy_info->attached, &sas_device,
2764 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002765
Eric Mooreb506ade2007-01-29 09:45:37 -07002766 if (phy_info->attached.device_info &
2767 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787e2006-01-26 16:20:06 -07002768 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002769 if (phy_info->attached.device_info &
2770 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787e2006-01-26 16:20:06 -07002771 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002772 if (phy_info->attached.device_info &
2773 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787e2006-01-26 16:20:06 -07002774 ds = "sata";
2775
2776 printk(MYIOC_s_INFO_FMT
2777 "attaching %s device, channel %d, id %d, phy %d\n",
2778 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2779
James Bottomleyf013db32006-03-18 14:54:36 -06002780 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002781 rphy = sas_end_device_alloc(port);
2782 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302783 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002784 "%s: exit at line=%d\n", ioc->name,
2785 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002786 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002787 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002788
James Bottomleyf013db32006-03-18 14:54:36 -06002789 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002790 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302791 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002792 "%s: exit at line=%d\n", ioc->name,
2793 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002794 sas_rphy_free(rphy);
2795 break;
2796 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302797 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002798 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07002799 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002800 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2801 ev->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07002802 if (sdev) {
2803 scsi_device_put(sdev);
2804 break;
2805 }
2806 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002807 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002808 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2809 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07002810 mpt_findImVolumes(ioc);
2811 break;
2812 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002813 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002814 ev->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07002815 if (!sdev)
2816 break;
2817 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002818 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002819 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002820 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07002821 scsi_remove_device(sdev);
2822 scsi_device_put(sdev);
2823 mpt_findImVolumes(ioc);
2824 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002825 case MPTSAS_ADD_INACTIVE_VOLUME:
2826 mptsas_adding_inactive_raid_components(ioc,
2827 ev->channel, ev->id);
2828 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002829 case MPTSAS_IGNORE_EVENT:
2830 default:
2831 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002832 }
2833
Moore, Erice6b2d762006-03-14 09:14:24 -07002834 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002835 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002836}
2837
2838static void
Eric Moore547f9a22006-06-27 14:42:12 -06002839mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002840 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2841{
2842 struct mptsas_hotplug_event *ev;
2843 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2844 __le64 sas_address;
2845
2846 if ((device_info &
2847 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2848 MPI_SAS_DEVICE_INFO_STP_TARGET |
2849 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2850 return;
2851
Moore, Eric4b766472006-03-14 09:14:12 -07002852 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002853 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002854
2855 mptsas_target_reset_queue(ioc, sas_event_data);
2856 break;
2857
2858 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002859 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002860 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002861 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002862 break;
2863 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002864
David Howellsc4028952006-11-22 14:57:56 +00002865 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002866 ev->ioc = ioc;
2867 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2868 ev->parent_handle =
2869 le16_to_cpu(sas_event_data->ParentDevHandle);
2870 ev->channel = sas_event_data->Bus;
2871 ev->id = sas_event_data->TargetID;
2872 ev->phy_id = sas_event_data->PhyNum;
2873 memcpy(&sas_address, &sas_event_data->SASAddress,
2874 sizeof(__le64));
2875 ev->sas_address = le64_to_cpu(sas_address);
2876 ev->device_info = device_info;
2877
2878 if (sas_event_data->ReasonCode &
2879 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2880 ev->event_type = MPTSAS_ADD_DEVICE;
2881 else
2882 ev->event_type = MPTSAS_DEL_DEVICE;
2883 schedule_work(&ev->work);
2884 break;
2885 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2886 /*
2887 * Persistent table is full.
2888 */
Eric Moore547f9a22006-06-27 14:42:12 -06002889 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002890 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002891 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002892 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002893 /*
2894 * TODO, handle other events
2895 */
Moore, Eric4b766472006-03-14 09:14:12 -07002896 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002897 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002898 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002899 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2900 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2901 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2902 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002903 default:
2904 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002905 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002906}
Moore, Ericc73787e2006-01-26 16:20:06 -07002907static void
Eric Moore547f9a22006-06-27 14:42:12 -06002908mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787e2006-01-26 16:20:06 -07002909 EVENT_DATA_RAID *raid_event_data)
2910{
2911 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002912 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2913 int state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07002914
2915 if (ioc->bus_type != SAS)
2916 return;
2917
Eric Moore547f9a22006-06-27 14:42:12 -06002918 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787e2006-01-26 16:20:06 -07002919 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002920 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787e2006-01-26 16:20:06 -07002921 return;
2922 }
2923
David Howellsc4028952006-11-22 14:57:56 +00002924 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787e2006-01-26 16:20:06 -07002925 ev->ioc = ioc;
2926 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002927 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002928 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787e2006-01-26 16:20:06 -07002929
2930 switch (raid_event_data->ReasonCode) {
2931 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002932 ev->phys_disk_num_valid = 1;
2933 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787e2006-01-26 16:20:06 -07002934 ev->event_type = MPTSAS_ADD_DEVICE;
2935 break;
2936 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002937 ev->phys_disk_num_valid = 1;
2938 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002939 ev->hidden_raid_component = 1;
Moore, Ericc73787e2006-01-26 16:20:06 -07002940 ev->event_type = MPTSAS_DEL_DEVICE;
2941 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002942 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2943 switch (state) {
2944 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002945 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002946 ev->phys_disk_num_valid = 1;
2947 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002948 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002949 ev->event_type = MPTSAS_ADD_DEVICE;
2950 break;
2951 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002952 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2953 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2954 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002955 ev->phys_disk_num_valid = 1;
2956 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002957 ev->event_type = MPTSAS_DEL_DEVICE;
2958 break;
2959 default:
2960 break;
2961 }
2962 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07002963 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2964 ev->event_type = MPTSAS_DEL_RAID;
2965 break;
2966 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2967 ev->event_type = MPTSAS_ADD_RAID;
2968 break;
2969 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002970 switch (state) {
2971 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2972 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2973 ev->event_type = MPTSAS_DEL_RAID;
2974 break;
2975 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2976 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2977 ev->event_type = MPTSAS_ADD_RAID;
2978 break;
2979 default:
2980 break;
2981 }
Moore, Ericc73787e2006-01-26 16:20:06 -07002982 break;
2983 default:
2984 break;
2985 }
2986 schedule_work(&ev->work);
2987}
2988
Moore, Erice6b2d762006-03-14 09:14:24 -07002989static void
Eric Moore547f9a22006-06-27 14:42:12 -06002990mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002991 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2992{
2993 struct mptsas_discovery_event *ev;
2994
2995 /*
2996 * DiscoveryStatus
2997 *
2998 * This flag will be non-zero when firmware
2999 * kicks off discovery, and return to zero
3000 * once its completed.
3001 */
3002 if (discovery_data->DiscoveryStatus)
3003 return;
3004
Eric Moore547f9a22006-06-27 14:42:12 -06003005 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003006 if (!ev)
3007 return;
David Howellsc4028952006-11-22 14:57:56 +00003008 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003009 ev->ioc = ioc;
3010 schedule_work(&ev->work);
3011};
3012
Eric Mooreb506ade2007-01-29 09:45:37 -07003013/*
3014 * mptsas_send_ir2_event - handle exposing hidden disk when
3015 * an inactive raid volume is added
3016 *
3017 * @ioc: Pointer to MPT_ADAPTER structure
3018 * @ir2_data
3019 *
3020 */
3021static void
3022mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3023{
3024 struct mptsas_hotplug_event *ev;
3025
3026 if (ir2_data->ReasonCode !=
3027 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3028 return;
3029
3030 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3031 if (!ev)
3032 return;
3033
3034 INIT_WORK(&ev->work, mptsas_hotplug_work);
3035 ev->ioc = ioc;
3036 ev->id = ir2_data->TargetID;
3037 ev->channel = ir2_data->Bus;
3038 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3039
3040 schedule_work(&ev->work);
3041};
Moore, Erice6b2d762006-03-14 09:14:24 -07003042
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003043static int
3044mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3045{
Moore, Ericc73787e2006-01-26 16:20:06 -07003046 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003047 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3048
3049 if (!ioc->sh)
Moore, Ericc73787e2006-01-26 16:20:06 -07003050 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003051
Moore, Erice6b2d762006-03-14 09:14:24 -07003052 /*
3053 * sas_discovery_ignore_events
3054 *
3055 * This flag is to prevent anymore processing of
3056 * sas events once mptsas_remove function is called.
3057 */
3058 if (ioc->sas_discovery_ignore_events) {
3059 rc = mptscsih_event_process(ioc, reply);
3060 goto out;
3061 }
3062
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003063 switch (event) {
3064 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003065 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003066 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787e2006-01-26 16:20:06 -07003067 break;
3068 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003069 mptsas_send_raid_event(ioc,
Moore, Ericc73787e2006-01-26 16:20:06 -07003070 (EVENT_DATA_RAID *)reply->Data);
3071 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003072 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003073 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003074 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003075 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003076 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003077 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003078 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003079 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3080 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003081 case MPI_EVENT_IR2:
3082 mptsas_send_ir2_event(ioc,
3083 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3084 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003085 default:
Moore, Ericc73787e2006-01-26 16:20:06 -07003086 rc = mptscsih_event_process(ioc, reply);
3087 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003088 }
Moore, Ericc73787e2006-01-26 16:20:06 -07003089 out:
3090
3091 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003092}
3093
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003094static int
3095mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3096{
3097 struct Scsi_Host *sh;
3098 MPT_SCSI_HOST *hd;
3099 MPT_ADAPTER *ioc;
3100 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003101 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003102 int numSGE = 0;
3103 int scale;
3104 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003105 int error=0;
3106 int r;
3107
3108 r = mpt_attach(pdev,id);
3109 if (r)
3110 return r;
3111
3112 ioc = pci_get_drvdata(pdev);
3113 ioc->DoneCtx = mptsasDoneCtx;
3114 ioc->TaskCtx = mptsasTaskCtx;
3115 ioc->InternalCtx = mptsasInternalCtx;
3116
3117 /* Added sanity check on readiness of the MPT adapter.
3118 */
3119 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3120 printk(MYIOC_s_WARN_FMT
3121 "Skipping because it's not operational!\n",
3122 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003123 error = -ENODEV;
3124 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003125 }
3126
3127 if (!ioc->active) {
3128 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3129 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003130 error = -ENODEV;
3131 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003132 }
3133
3134 /* Sanity check - ensure at least 1 port is INITIATOR capable
3135 */
3136 ioc_cap = 0;
3137 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3138 if (ioc->pfacts[ii].ProtocolFlags &
3139 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3140 ioc_cap++;
3141 }
3142
3143 if (!ioc_cap) {
3144 printk(MYIOC_s_WARN_FMT
3145 "Skipping ioc=%p because SCSI Initiator mode "
3146 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003147 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003148 }
3149
3150 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3151 if (!sh) {
3152 printk(MYIOC_s_WARN_FMT
3153 "Unable to register controller with SCSI subsystem\n",
3154 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003155 error = -1;
3156 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003157 }
3158
3159 spin_lock_irqsave(&ioc->FreeQlock, flags);
3160
3161 /* Attach the SCSI Host to the IOC structure
3162 */
3163 ioc->sh = sh;
3164
3165 sh->io_port = 0;
3166 sh->n_io_port = 0;
3167 sh->irq = 0;
3168
3169 /* set 16 byte cdb's */
3170 sh->max_cmd_len = 16;
3171
Eric Moore793955f2007-01-29 09:42:20 -07003172 sh->max_id = ioc->pfacts[0].PortSCSIID;
3173 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003174
3175 sh->transportt = mptsas_transport_template;
3176
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003177 sh->this_id = ioc->pfacts[0].PortSCSIID;
3178
3179 /* Required entry.
3180 */
3181 sh->unique_id = ioc->id;
3182
3183 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003184 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003185 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003186 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003187 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003188
3189 /* Verify that we won't exceed the maximum
3190 * number of chain buffers
3191 * We can optimize: ZZ = req_sz/sizeof(SGE)
3192 * For 32bit SGE's:
3193 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3194 * + (req_sz - 64)/sizeof(SGE)
3195 * A slightly different algorithm is required for
3196 * 64bit SGEs.
3197 */
3198 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3199 if (sizeof(dma_addr_t) == sizeof(u64)) {
3200 numSGE = (scale - 1) *
3201 (ioc->facts.MaxChainDepth-1) + scale +
3202 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3203 sizeof(u32));
3204 } else {
3205 numSGE = 1 + (scale - 1) *
3206 (ioc->facts.MaxChainDepth-1) + scale +
3207 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3208 sizeof(u32));
3209 }
3210
3211 if (numSGE < sh->sg_tablesize) {
3212 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303213 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003214 "Resetting sg_tablesize to %d from %d\n",
3215 ioc->name, numSGE, sh->sg_tablesize));
3216 sh->sg_tablesize = numSGE;
3217 }
3218
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003219 hd = (MPT_SCSI_HOST *) sh->hostdata;
3220 hd->ioc = ioc;
3221
3222 /* SCSI needs scsi_cmnd lookup table!
3223 * (with size equal to req_depth*PtrSz!)
3224 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003225 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3226 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003227 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003228 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003229 }
3230
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303231 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003232 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003233
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 /* Clear the TM flags
3235 */
3236 hd->tmPending = 0;
3237 hd->tmState = TM_STATE_NONE;
3238 hd->resetPending = 0;
3239 hd->abortSCpnt = NULL;
3240
3241 /* Clear the pointer used to store
3242 * single-threaded commands, i.e., those
3243 * issued during a bus scan, dv and
3244 * configuration pages.
3245 */
3246 hd->cmdPtr = NULL;
3247
3248 /* Initialize this SCSI Hosts' timers
3249 * To use, set the timer expires field
3250 * and add_timer
3251 */
3252 init_timer(&hd->timer);
3253 hd->timer.data = (unsigned long) hd;
3254 hd->timer.function = mptscsih_timer_expired;
3255
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003256 ioc->sas_data.ptClear = mpt_pt_clear;
3257
Eric Mooredf9e0622007-01-29 09:46:21 -07003258 init_waitqueue_head(&hd->scandv_waitq);
3259 hd->scandv_wait_done = 0;
3260 hd->last_queue_full = 0;
3261 INIT_LIST_HEAD(&hd->target_reset_list);
3262 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3263
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003264 if (ioc->sas_data.ptClear==1) {
3265 mptbase_sas_persist_operation(
3266 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3267 }
3268
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003269 error = scsi_add_host(sh, &ioc->pcidev->dev);
3270 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003271 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3272 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003273 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003274 }
3275
3276 mptsas_scan_sas_topology(ioc);
3277
3278 return 0;
3279
Eric Moore547f9a22006-06-27 14:42:12 -06003280 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003281
3282 mptscsih_remove(pdev);
3283 return error;
3284}
3285
3286static void __devexit mptsas_remove(struct pci_dev *pdev)
3287{
3288 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3289 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003290 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003291
Eric Mooreb506ade2007-01-29 09:45:37 -07003292 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293 sas_remove_host(ioc->sh);
3294
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003295 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003296 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3297 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003298 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303299 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003300 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003301 kfree(p);
3302 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003303 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003304
3305 mptscsih_remove(pdev);
3306}
3307
3308static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003309 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003310 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003311 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003312 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003313 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003314 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003315 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003316 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003317 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003318 PCI_ANY_ID, PCI_ANY_ID },
3319 {0} /* Terminating entry */
3320};
3321MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3322
3323
3324static struct pci_driver mptsas_driver = {
3325 .name = "mptsas",
3326 .id_table = mptsas_pci_table,
3327 .probe = mptsas_probe,
3328 .remove = __devexit_p(mptsas_remove),
3329 .shutdown = mptscsih_shutdown,
3330#ifdef CONFIG_PM
3331 .suspend = mptscsih_suspend,
3332 .resume = mptscsih_resume,
3333#endif
3334};
3335
3336static int __init
3337mptsas_init(void)
3338{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303339 int error;
3340
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003341 show_mptmod_ver(my_NAME, my_VERSION);
3342
3343 mptsas_transport_template =
3344 sas_attach_transport(&mptsas_transport_functions);
3345 if (!mptsas_transport_template)
3346 return -ENODEV;
3347
3348 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003349 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003350 mptsasInternalCtx =
3351 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003352 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003353
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303354 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3355 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003356
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303357 error = pci_register_driver(&mptsas_driver);
3358 if (error)
3359 sas_release_transport(mptsas_transport_template);
3360
3361 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003362}
3363
3364static void __exit
3365mptsas_exit(void)
3366{
3367 pci_unregister_driver(&mptsas_driver);
3368 sas_release_transport(mptsas_transport_template);
3369
3370 mpt_reset_deregister(mptsasDoneCtx);
3371 mpt_event_deregister(mptsasDoneCtx);
3372
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003373 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003374 mpt_deregister(mptsasInternalCtx);
3375 mpt_deregister(mptsasTaskCtx);
3376 mpt_deregister(mptsasDoneCtx);
3377}
3378
3379module_init(mptsas_init);
3380module_exit(mptsas_exit);