blob: 4333449ae654052dec3747f9b8c613a625c23cef [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{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530103 dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
104 dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
105 le16_to_cpu(phy_data->AttachedDeviceHandle)));
106 dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
107 le16_to_cpu(phy_data->ControllerDevHandle)));
108 dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
109 dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
110 dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
111 dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
112 dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
113 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
114 dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
115 le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200116}
117
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530118static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200119{
120 __le64 sas_address;
121
122 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
123
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530124 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
125 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
126 le16_to_cpu(pg0->AttachedDevHandle)));
127 dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
128 (unsigned long long)le64_to_cpu(sas_address)));
129 dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
130 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
131 le32_to_cpu(pg0->AttachedDeviceInfo)));
132 dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
133 dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
134 dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200135}
136
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530137static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200138{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530139 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
140 dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
141 dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
142 pg1->RunningDisparityErrorCount));
143 dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
144 dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200145}
146
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530147static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200148{
149 __le64 sas_address;
150
151 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
152
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530153 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
154 dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
155 dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
156 dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
157 dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
158 dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
159 le64_to_cpu(sas_address)));
160 dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
161 dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200162 /* The PhyNum field specifies the PHY number of the parent
163 * device this device is linked to
164 */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530165 dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
166 dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
167 dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
168 dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
169 dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200170}
171
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530172static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200173{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530174 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
175 dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
176 dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
177 dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
178 dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
179 dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
180 dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
181 le16_to_cpu(pg1->OwnerDevHandle)));
182 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
183 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200184}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200185
Christoph Hellwige3094442006-02-16 13:25:36 +0100186static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
187{
188 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
189 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
190}
191
192static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
193{
194 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
195 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
196}
197
Moore, Erice6b2d762006-03-14 09:14:24 -0700198/*
199 * mptsas_find_portinfo_by_handle
200 *
201 * This function should be called with the sas_topology_mutex already held
202 */
203static struct mptsas_portinfo *
204mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
205{
206 struct mptsas_portinfo *port_info, *rc=NULL;
207 int i;
208
209 list_for_each_entry(port_info, &ioc->sas_topology, list)
210 for (i = 0; i < port_info->num_phys; i++)
211 if (port_info->phy_info[i].identify.handle == handle) {
212 rc = port_info;
213 goto out;
214 }
215 out:
216 return rc;
217}
218
Moore, Ericbd23e942006-04-17 12:43:04 -0600219/*
220 * Returns true if there is a scsi end device
221 */
222static inline int
223mptsas_is_end_device(struct mptsas_devinfo * attached)
224{
Eric Moore547f9a22006-06-27 14:42:12 -0600225 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600226 (attached->device_info &
227 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
228 ((attached->device_info &
229 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
230 (attached->device_info &
231 MPI_SAS_DEVICE_INFO_STP_TARGET) |
232 (attached->device_info &
233 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
234 return 1;
235 else
236 return 0;
237}
238
Eric Moore547f9a22006-06-27 14:42:12 -0600239/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600240static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530241mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600242{
243 struct mptsas_portinfo *port_info;
244 struct mptsas_phyinfo *phy_info;
245 u8 i;
246
247 if (!port_details)
248 return;
249
250 port_info = port_details->port_info;
251 phy_info = port_info->phy_info;
252
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530253 dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700254 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
255 port_details->num_phys, (unsigned long long)
256 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600257
258 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
259 if(phy_info->port_details != port_details)
260 continue;
261 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
262 phy_info->port_details = NULL;
263 }
264 kfree(port_details);
265}
266
267static inline struct sas_rphy *
268mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
269{
270 if (phy_info->port_details)
271 return phy_info->port_details->rphy;
272 else
273 return NULL;
274}
275
276static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530277mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600278{
279 if (phy_info->port_details) {
280 phy_info->port_details->rphy = rphy;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530281 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600282 }
283
Eric Moore547f9a22006-06-27 14:42:12 -0600284 if (rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530285 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
286 &rphy->dev, "add:"));
287 dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
288 rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600289 }
Eric Moore547f9a22006-06-27 14:42:12 -0600290}
291
292static inline struct sas_port *
293mptsas_get_port(struct mptsas_phyinfo *phy_info)
294{
295 if (phy_info->port_details)
296 return phy_info->port_details->port;
297 else
298 return NULL;
299}
300
301static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530302mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600303{
304 if (phy_info->port_details)
305 phy_info->port_details->port = port;
306
Eric Moore547f9a22006-06-27 14:42:12 -0600307 if (port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530308 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
309 &port->dev, "add:"));
310 dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
311 port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600312 }
Eric Moore547f9a22006-06-27 14:42:12 -0600313}
314
315static inline struct scsi_target *
316mptsas_get_starget(struct mptsas_phyinfo *phy_info)
317{
318 if (phy_info->port_details)
319 return phy_info->port_details->starget;
320 else
321 return NULL;
322}
323
324static inline void
325mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
326starget)
327{
328 if (phy_info->port_details)
329 phy_info->port_details->starget = starget;
330}
331
332
333/*
334 * mptsas_setup_wide_ports
335 *
336 * Updates for new and existing narrow/wide port configuration
337 * in the sas_topology
338 */
Eric Moore376ac832006-06-29 17:36:26 -0600339static void
Eric Moore547f9a22006-06-27 14:42:12 -0600340mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
341{
342 struct mptsas_portinfo_details * port_details;
343 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
344 u64 sas_address;
345 int i, j;
346
347 mutex_lock(&ioc->sas_topology_mutex);
348
349 phy_info = port_info->phy_info;
350 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
351 if (phy_info->attached.handle)
352 continue;
353 port_details = phy_info->port_details;
354 if (!port_details)
355 continue;
356 if (port_details->num_phys < 2)
357 continue;
358 /*
359 * Removing a phy from a port, letting the last
360 * phy be removed by firmware events.
361 */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530362 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600363 "%s: [%p]: deleting phy = %d\n",
364 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600365 port_details->num_phys--;
366 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
367 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
368 sas_port_delete_phy(port_details->port, phy_info->phy);
369 phy_info->port_details = NULL;
370 }
371
372 /*
373 * Populate and refresh the tree
374 */
375 phy_info = port_info->phy_info;
376 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
377 sas_address = phy_info->attached.sas_address;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530378 dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700379 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600380 if (!sas_address)
381 continue;
382 port_details = phy_info->port_details;
383 /*
384 * Forming a port
385 */
386 if (!port_details) {
387 port_details = kzalloc(sizeof(*port_details),
388 GFP_KERNEL);
389 if (!port_details)
390 goto out;
391 port_details->num_phys = 1;
392 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600393 if (phy_info->phy_id < 64 )
394 port_details->phy_bitmask |=
395 (1 << phy_info->phy_id);
396 phy_info->sas_port_add_phy=1;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530397 dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700398 "phy_id=%d sas_address=0x%018llX\n",
399 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600400 phy_info->port_details = port_details;
401 }
402
403 if (i == port_info->num_phys - 1)
404 continue;
405 phy_info_cmp = &port_info->phy_info[i + 1];
406 for (j = i + 1 ; j < port_info->num_phys ; j++,
407 phy_info_cmp++) {
408 if (!phy_info_cmp->attached.sas_address)
409 continue;
410 if (sas_address != phy_info_cmp->attached.sas_address)
411 continue;
412 if (phy_info_cmp->port_details == port_details )
413 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530414 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700415 "\t\tphy_id=%d sas_address=0x%018llX\n",
416 j, (unsigned long long)
417 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600418 if (phy_info_cmp->port_details) {
419 port_details->rphy =
420 mptsas_get_rphy(phy_info_cmp);
421 port_details->port =
422 mptsas_get_port(phy_info_cmp);
423 port_details->starget =
424 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600425 port_details->num_phys =
426 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600427 if (!phy_info_cmp->port_details->num_phys)
428 kfree(phy_info_cmp->port_details);
429 } else
430 phy_info_cmp->sas_port_add_phy=1;
431 /*
432 * Adding a phy to a port
433 */
434 phy_info_cmp->port_details = port_details;
435 if (phy_info_cmp->phy_id < 64 )
436 port_details->phy_bitmask |=
437 (1 << phy_info_cmp->phy_id);
438 port_details->num_phys++;
439 }
440 }
441
442 out:
443
Eric Moore547f9a22006-06-27 14:42:12 -0600444 for (i = 0; i < port_info->num_phys; i++) {
445 port_details = port_info->phy_info[i].port_details;
446 if (!port_details)
447 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530448 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700449 "%s: [%p]: phy_id=%02d num_phys=%02d "
450 "bitmask=0x%016llX\n", __FUNCTION__,
451 port_details, i, port_details->num_phys,
452 (unsigned long long)port_details->phy_bitmask));
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530453 dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
Eric Moore547f9a22006-06-27 14:42:12 -0600454 port_details->port, port_details->rphy));
455 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530456 dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600457 mutex_unlock(&ioc->sas_topology_mutex);
458}
459
Eric Mooredf9e0622007-01-29 09:46:21 -0700460/**
461 * csmisas_find_vtarget
462 *
463 * @ioc
464 * @volume_id
465 * @volume_bus
466 *
467 **/
468static VirtTarget *
469mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600470{
Eric Mooredf9e0622007-01-29 09:46:21 -0700471 struct scsi_device *sdev;
472 VirtDevice *vdev;
473 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600474
Eric Mooredf9e0622007-01-29 09:46:21 -0700475 shost_for_each_device(sdev, ioc->sh) {
476 if ((vdev = sdev->hostdata) == NULL)
477 continue;
478 if (vdev->vtarget->id == id &&
479 vdev->vtarget->channel == channel)
480 vtarget = vdev->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600481 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700482 return vtarget;
483}
484
485/**
486 * mptsas_target_reset
487 *
488 * Issues TARGET_RESET to end device using handshaking method
489 *
490 * @ioc
491 * @channel
492 * @id
493 *
494 * Returns (1) success
495 * (0) failure
496 *
497 **/
498static int
499mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
500{
501 MPT_FRAME_HDR *mf;
502 SCSITaskMgmt_t *pScsiTm;
503
504 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530505 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700506 ioc->name,__FUNCTION__, __LINE__));
507 return 0;
508 }
509
510 /* Format the Request
511 */
512 pScsiTm = (SCSITaskMgmt_t *) mf;
513 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
514 pScsiTm->TargetID = id;
515 pScsiTm->Bus = channel;
516 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
517 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
518 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
519
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530520 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700521
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530522 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700523
524 return 1;
525}
526
527/**
528 * mptsas_target_reset_queue
529 *
530 * Receive request for TARGET_RESET after recieving an firmware
531 * event NOT_RESPONDING_EVENT, then put command in link list
532 * and queue if task_queue already in use.
533 *
534 * @ioc
535 * @sas_event_data
536 *
537 **/
538static void
539mptsas_target_reset_queue(MPT_ADAPTER *ioc,
540 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
541{
542 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
543 VirtTarget *vtarget = NULL;
544 struct mptsas_target_reset_event *target_reset_list;
545 u8 id, channel;
546
547 id = sas_event_data->TargetID;
548 channel = sas_event_data->Bus;
549
550 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
551 return;
552
553 vtarget->deleted = 1; /* block IO */
554
555 target_reset_list = kzalloc(sizeof(*target_reset_list),
556 GFP_ATOMIC);
557 if (!target_reset_list) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530558 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700559 ioc->name,__FUNCTION__, __LINE__));
560 return;
561 }
562
563 memcpy(&target_reset_list->sas_event_data, sas_event_data,
564 sizeof(*sas_event_data));
565 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
566
567 if (hd->resetPending)
568 return;
569
570 if (mptsas_target_reset(ioc, channel, id)) {
571 target_reset_list->target_reset_issued = 1;
572 hd->resetPending = 1;
573 }
574}
575
576/**
577 * mptsas_dev_reset_complete
578 *
579 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
580 * enable work queue to finish off removing device from upper layers.
581 * then send next TARGET_RESET in the queue.
582 *
583 * @ioc
584 *
585 **/
586static void
587mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
588{
589 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
590 struct list_head *head = &hd->target_reset_list;
591 struct mptsas_target_reset_event *target_reset_list;
592 struct mptsas_hotplug_event *ev;
593 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
594 u8 id, channel;
595 __le64 sas_address;
596
597 if (list_empty(head))
598 return;
599
600 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
601
602 sas_event_data = &target_reset_list->sas_event_data;
603 id = sas_event_data->TargetID;
604 channel = sas_event_data->Bus;
605 hd->resetPending = 0;
606
607 /*
608 * retry target reset
609 */
610 if (!target_reset_list->target_reset_issued) {
611 if (mptsas_target_reset(ioc, channel, id)) {
612 target_reset_list->target_reset_issued = 1;
613 hd->resetPending = 1;
614 }
615 return;
616 }
617
618 /*
619 * enable work queue to remove device from upper layers
620 */
621 list_del(&target_reset_list->list);
622
623 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
624 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530625 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700626 ioc->name,__FUNCTION__, __LINE__));
627 return;
628 }
629
630 INIT_WORK(&ev->work, mptsas_hotplug_work);
631 ev->ioc = ioc;
632 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
633 ev->parent_handle =
634 le16_to_cpu(sas_event_data->ParentDevHandle);
635 ev->channel = channel;
636 ev->id =id;
637 ev->phy_id = sas_event_data->PhyNum;
638 memcpy(&sas_address, &sas_event_data->SASAddress,
639 sizeof(__le64));
640 ev->sas_address = le64_to_cpu(sas_address);
641 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
642 ev->event_type = MPTSAS_DEL_DEVICE;
643 schedule_work(&ev->work);
644 kfree(target_reset_list);
645
646 /*
647 * issue target reset to next device in the queue
648 */
649
650 head = &hd->target_reset_list;
651 if (list_empty(head))
652 return;
653
654 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
655 list);
656
657 sas_event_data = &target_reset_list->sas_event_data;
658 id = sas_event_data->TargetID;
659 channel = sas_event_data->Bus;
660
661 if (mptsas_target_reset(ioc, channel, id)) {
662 target_reset_list->target_reset_issued = 1;
663 hd->resetPending = 1;
664 }
665}
666
667/**
668 * mptsas_taskmgmt_complete
669 *
670 * @ioc
671 * @mf
672 * @mr
673 *
674 **/
675static int
676mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
677{
678 mptsas_dev_reset_complete(ioc);
679 return mptscsih_taskmgmt_complete(ioc, mf, mr);
680}
681
682/**
683 * mptscsih_ioc_reset
684 *
685 * @ioc
686 * @reset_phase
687 *
688 **/
689static int
690mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
691{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800692 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700693 struct mptsas_target_reset_event *target_reset_list, *n;
694 int rc;
695
696 rc = mptscsih_ioc_reset(ioc, reset_phase);
697
698 if (ioc->bus_type != SAS)
699 goto out;
700
701 if (reset_phase != MPT_IOC_POST_RESET)
702 goto out;
703
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800704 if (!ioc->sh || !ioc->sh->hostdata)
705 goto out;
706 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
707 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700708 goto out;
709
710 if (list_empty(&hd->target_reset_list))
711 goto out;
712
713 /* flush the target_reset_list */
714 list_for_each_entry_safe(target_reset_list, n,
715 &hd->target_reset_list, list) {
716 list_del(&target_reset_list->list);
717 kfree(target_reset_list);
718 }
719
720 out:
721 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600722}
723
Christoph Hellwige3094442006-02-16 13:25:36 +0100724static int
Moore, Eric52435432006-03-14 09:14:15 -0700725mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100726 u32 form, u32 form_specific)
727{
728 ConfigExtendedPageHeader_t hdr;
729 CONFIGPARMS cfg;
730 SasEnclosurePage0_t *buffer;
731 dma_addr_t dma_handle;
732 int error;
733 __le64 le_identifier;
734
735 memset(&hdr, 0, sizeof(hdr));
736 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
737 hdr.PageNumber = 0;
738 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
739 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
740
741 cfg.cfghdr.ehdr = &hdr;
742 cfg.physAddr = -1;
743 cfg.pageAddr = form + form_specific;
744 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
745 cfg.dir = 0; /* read */
746 cfg.timeout = 10;
747
748 error = mpt_config(ioc, &cfg);
749 if (error)
750 goto out;
751 if (!hdr.ExtPageLength) {
752 error = -ENXIO;
753 goto out;
754 }
755
756 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
757 &dma_handle);
758 if (!buffer) {
759 error = -ENOMEM;
760 goto out;
761 }
762
763 cfg.physAddr = dma_handle;
764 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
765
766 error = mpt_config(ioc, &cfg);
767 if (error)
768 goto out_free_consistent;
769
770 /* save config data */
771 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
772 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
773 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
774 enclosure->flags = le16_to_cpu(buffer->Flags);
775 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
776 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
777 enclosure->start_id = buffer->StartTargetID;
778 enclosure->start_channel = buffer->StartBus;
779 enclosure->sep_id = buffer->SEPTargetID;
780 enclosure->sep_channel = buffer->SEPBus;
781
782 out_free_consistent:
783 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
784 buffer, dma_handle);
785 out:
786 return error;
787}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200788
James Bottomleyf013db32006-03-18 14:54:36 -0600789static int
790mptsas_slave_configure(struct scsi_device *sdev)
791{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600792
James Bottomleye8bf3942006-07-11 17:49:34 -0400793 if (sdev->channel == MPTSAS_RAID_CHANNEL)
794 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600795
James Bottomleye8bf3942006-07-11 17:49:34 -0400796 sas_read_port_mode_page(sdev);
797
798 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600799 return mptscsih_slave_configure(sdev);
800}
801
Eric Moore547f9a22006-06-27 14:42:12 -0600802static int
803mptsas_target_alloc(struct scsi_target *starget)
804{
805 struct Scsi_Host *host = dev_to_shost(&starget->dev);
806 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
807 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700808 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600809 struct sas_rphy *rphy;
810 struct mptsas_portinfo *p;
811 int i;
812
813 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
814 if (!vtarget)
815 return -ENOMEM;
816
817 vtarget->starget = starget;
818 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700819 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
820 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600821 channel = 0;
822
Eric Moore793955f2007-01-29 09:42:20 -0700823 /*
824 * RAID volumes placed beyond the last expected port.
825 */
826 if (starget->channel == MPTSAS_RAID_CHANNEL) {
827 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
828 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
829 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600830 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700831 }
Eric Moore547f9a22006-06-27 14:42:12 -0600832
833 rphy = dev_to_rphy(starget->dev.parent);
834 mutex_lock(&hd->ioc->sas_topology_mutex);
835 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
836 for (i = 0; i < p->num_phys; i++) {
837 if (p->phy_info[i].attached.sas_address !=
838 rphy->identify.sas_address)
839 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700840 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600841 channel = p->phy_info[i].attached.channel;
842 mptsas_set_starget(&p->phy_info[i], starget);
843
844 /*
845 * Exposing hidden raid components
846 */
Eric Moore793955f2007-01-29 09:42:20 -0700847 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
848 id = mptscsih_raid_id_to_num(hd->ioc,
849 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600850 vtarget->tflags |=
851 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700852 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600853 }
854 mutex_unlock(&hd->ioc->sas_topology_mutex);
855 goto out;
856 }
857 }
858 mutex_unlock(&hd->ioc->sas_topology_mutex);
859
860 kfree(vtarget);
861 return -ENXIO;
862
863 out:
Eric Moore793955f2007-01-29 09:42:20 -0700864 vtarget->id = id;
865 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600866 starget->hostdata = vtarget;
867 return 0;
868}
869
870static void
871mptsas_target_destroy(struct scsi_target *starget)
872{
873 struct Scsi_Host *host = dev_to_shost(&starget->dev);
874 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
875 struct sas_rphy *rphy;
876 struct mptsas_portinfo *p;
877 int i;
878
879 if (!starget->hostdata)
880 return;
881
James Bottomleye8bf3942006-07-11 17:49:34 -0400882 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600883 goto out;
884
885 rphy = dev_to_rphy(starget->dev.parent);
886 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
887 for (i = 0; i < p->num_phys; i++) {
888 if (p->phy_info[i].attached.sas_address !=
889 rphy->identify.sas_address)
890 continue;
891 mptsas_set_starget(&p->phy_info[i], NULL);
892 goto out;
893 }
894 }
895
896 out:
897 kfree(starget->hostdata);
898 starget->hostdata = NULL;
899}
900
901
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200902static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700903mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200904{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700905 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200906 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
907 struct sas_rphy *rphy;
908 struct mptsas_portinfo *p;
909 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700910 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600911 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200912
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100913 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200914 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -0600915 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200916 hd->ioc->name, sizeof(VirtDevice));
917 return -ENOMEM;
918 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700919 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -0600920 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200921
James Bottomleye8bf3942006-07-11 17:49:34 -0400922 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -0700923 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700924
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700925 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100926 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200927 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
928 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600929 if (p->phy_info[i].attached.sas_address !=
930 rphy->identify.sas_address)
931 continue;
932 vdev->lun = sdev->lun;
933 /*
934 * Exposing hidden raid components
935 */
936 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700937 p->phy_info[i].attached.channel,
938 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -0600939 sdev->no_uld_attach = 1;
940 mutex_unlock(&hd->ioc->sas_topology_mutex);
941 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200942 }
943 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100944 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200945
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200946 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100947 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200948
949 out:
Eric Moore547f9a22006-06-27 14:42:12 -0600950 vdev->vtarget->num_luns++;
951 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200952 return 0;
953}
954
Eric Moore547f9a22006-06-27 14:42:12 -0600955static int
956mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100957{
Eric Moore547f9a22006-06-27 14:42:12 -0600958 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100959
Eric Moore793955f2007-01-29 09:42:20 -0700960 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -0600961 SCpnt->result = DID_NO_CONNECT << 16;
962 done(SCpnt);
963 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700964 }
Eric Moore547f9a22006-06-27 14:42:12 -0600965
Eric Moore793955f2007-01-29 09:42:20 -0700966// scsi_print_command(SCpnt);
967
Eric Moore547f9a22006-06-27 14:42:12 -0600968 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100969}
970
Eric Moore547f9a22006-06-27 14:42:12 -0600971
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200972static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700973 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200974 .proc_name = "mptsas",
975 .proc_info = mptscsih_proc_info,
976 .name = "MPT SPI Host",
977 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -0600978 .queuecommand = mptsas_qcmd,
979 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200980 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -0600981 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -0600982 .target_destroy = mptsas_target_destroy,
983 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200984 .change_queue_depth = mptscsih_change_queue_depth,
985 .eh_abort_handler = mptscsih_abort,
986 .eh_device_reset_handler = mptscsih_dev_reset,
987 .eh_bus_reset_handler = mptscsih_bus_reset,
988 .eh_host_reset_handler = mptscsih_host_reset,
989 .bios_param = mptscsih_bios_param,
990 .can_queue = MPT_FC_CAN_QUEUE,
991 .this_id = -1,
992 .sg_tablesize = MPT_SCSI_SG_DEPTH,
993 .max_sectors = 8192,
994 .cmd_per_lun = 7,
995 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530996 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200997};
998
Christoph Hellwigb5141122005-10-28 22:07:41 +0200999static int mptsas_get_linkerrors(struct sas_phy *phy)
1000{
1001 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1002 ConfigExtendedPageHeader_t hdr;
1003 CONFIGPARMS cfg;
1004 SasPhyPage1_t *buffer;
1005 dma_addr_t dma_handle;
1006 int error;
1007
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001008 /* FIXME: only have link errors on local phys */
1009 if (!scsi_is_sas_phy_local(phy))
1010 return -EINVAL;
1011
Christoph Hellwigb5141122005-10-28 22:07:41 +02001012 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1013 hdr.ExtPageLength = 0;
1014 hdr.PageNumber = 1 /* page number 1*/;
1015 hdr.Reserved1 = 0;
1016 hdr.Reserved2 = 0;
1017 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1018 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1019
1020 cfg.cfghdr.ehdr = &hdr;
1021 cfg.physAddr = -1;
1022 cfg.pageAddr = phy->identify.phy_identifier;
1023 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1024 cfg.dir = 0; /* read */
1025 cfg.timeout = 10;
1026
1027 error = mpt_config(ioc, &cfg);
1028 if (error)
1029 return error;
1030 if (!hdr.ExtPageLength)
1031 return -ENXIO;
1032
1033 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1034 &dma_handle);
1035 if (!buffer)
1036 return -ENOMEM;
1037
1038 cfg.physAddr = dma_handle;
1039 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1040
1041 error = mpt_config(ioc, &cfg);
1042 if (error)
1043 goto out_free_consistent;
1044
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301045 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001046
1047 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1048 phy->running_disparity_error_count =
1049 le32_to_cpu(buffer->RunningDisparityErrorCount);
1050 phy->loss_of_dword_sync_count =
1051 le32_to_cpu(buffer->LossDwordSynchCount);
1052 phy->phy_reset_problem_count =
1053 le32_to_cpu(buffer->PhyResetProblemCount);
1054
1055 out_free_consistent:
1056 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1057 buffer, dma_handle);
1058 return error;
1059}
1060
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001061static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1062 MPT_FRAME_HDR *reply)
1063{
1064 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1065 if (reply != NULL) {
1066 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1067 memcpy(ioc->sas_mgmt.reply, reply,
1068 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1069 }
1070 complete(&ioc->sas_mgmt.done);
1071 return 1;
1072}
1073
1074static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1075{
1076 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1077 SasIoUnitControlRequest_t *req;
1078 SasIoUnitControlReply_t *reply;
1079 MPT_FRAME_HDR *mf;
1080 MPIHeader_t *hdr;
1081 unsigned long timeleft;
1082 int error = -ERESTARTSYS;
1083
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001084 /* FIXME: fusion doesn't allow non-local phy reset */
1085 if (!scsi_is_sas_phy_local(phy))
1086 return -EINVAL;
1087
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001088 /* not implemented for expanders */
1089 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1090 return -ENXIO;
1091
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001092 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001093 goto out;
1094
1095 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1096 if (!mf) {
1097 error = -ENOMEM;
1098 goto out_unlock;
1099 }
1100
1101 hdr = (MPIHeader_t *) mf;
1102 req = (SasIoUnitControlRequest_t *)mf;
1103 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1104 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1105 req->MsgContext = hdr->MsgContext;
1106 req->Operation = hard_reset ?
1107 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1108 req->PhyNum = phy->identify.phy_identifier;
1109
1110 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1111
1112 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1113 10 * HZ);
1114 if (!timeleft) {
1115 /* On timeout reset the board */
1116 mpt_free_msg_frame(ioc, mf);
1117 mpt_HardResetHandler(ioc, CAN_SLEEP);
1118 error = -ETIMEDOUT;
1119 goto out_unlock;
1120 }
1121
1122 /* a reply frame is expected */
1123 if ((ioc->sas_mgmt.status &
1124 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1125 error = -ENXIO;
1126 goto out_unlock;
1127 }
1128
1129 /* process the completed Reply Message Frame */
1130 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1131 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1132 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1133 __FUNCTION__,
1134 reply->IOCStatus,
1135 reply->IOCLogInfo);
1136 error = -ENXIO;
1137 goto out_unlock;
1138 }
1139
1140 error = 0;
1141
1142 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001143 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001144 out:
1145 return error;
1146}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001147
Christoph Hellwige3094442006-02-16 13:25:36 +01001148static int
1149mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1150{
1151 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1152 int i, error;
1153 struct mptsas_portinfo *p;
1154 struct mptsas_enclosure enclosure_info;
1155 u64 enclosure_handle;
1156
1157 mutex_lock(&ioc->sas_topology_mutex);
1158 list_for_each_entry(p, &ioc->sas_topology, list) {
1159 for (i = 0; i < p->num_phys; i++) {
1160 if (p->phy_info[i].attached.sas_address ==
1161 rphy->identify.sas_address) {
1162 enclosure_handle = p->phy_info[i].
1163 attached.handle_enclosure;
1164 goto found_info;
1165 }
1166 }
1167 }
1168 mutex_unlock(&ioc->sas_topology_mutex);
1169 return -ENXIO;
1170
1171 found_info:
1172 mutex_unlock(&ioc->sas_topology_mutex);
1173 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001174 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001175 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1176 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1177 if (!error)
1178 *identifier = enclosure_info.enclosure_logical_id;
1179 return error;
1180}
1181
1182static int
1183mptsas_get_bay_identifier(struct sas_rphy *rphy)
1184{
1185 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1186 struct mptsas_portinfo *p;
1187 int i, rc;
1188
1189 mutex_lock(&ioc->sas_topology_mutex);
1190 list_for_each_entry(p, &ioc->sas_topology, list) {
1191 for (i = 0; i < p->num_phys; i++) {
1192 if (p->phy_info[i].attached.sas_address ==
1193 rphy->identify.sas_address) {
1194 rc = p->phy_info[i].attached.slot;
1195 goto out;
1196 }
1197 }
1198 }
1199 rc = -ENXIO;
1200 out:
1201 mutex_unlock(&ioc->sas_topology_mutex);
1202 return rc;
1203}
1204
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001205static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1206 struct request *req)
1207{
1208 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1209 MPT_FRAME_HDR *mf;
1210 SmpPassthroughRequest_t *smpreq;
1211 struct request *rsp = req->next_rq;
1212 int ret;
1213 int flagsLength;
1214 unsigned long timeleft;
1215 char *psge;
1216 dma_addr_t dma_addr_in = 0;
1217 dma_addr_t dma_addr_out = 0;
1218 u64 sas_address = 0;
1219
1220 if (!rsp) {
1221 printk(KERN_ERR "%s: the smp response space is missing\n",
1222 __FUNCTION__);
1223 return -EINVAL;
1224 }
1225
1226 /* do we need to support multiple segments? */
1227 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1228 printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
1229 __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1230 rsp->bio->bi_vcnt, rsp->data_len);
1231 return -EINVAL;
1232 }
1233
1234 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1235 if (ret)
1236 goto out;
1237
1238 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1239 if (!mf) {
1240 ret = -ENOMEM;
1241 goto out_unlock;
1242 }
1243
1244 smpreq = (SmpPassthroughRequest_t *)mf;
1245 memset(smpreq, 0, sizeof(*smpreq));
1246
1247 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1248 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1249
1250 if (rphy)
1251 sas_address = rphy->identify.sas_address;
1252 else {
1253 struct mptsas_portinfo *port_info;
1254
1255 mutex_lock(&ioc->sas_topology_mutex);
1256 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1257 if (port_info && port_info->phy_info)
1258 sas_address =
1259 port_info->phy_info[0].phy->identify.sas_address;
1260 mutex_unlock(&ioc->sas_topology_mutex);
1261 }
1262
1263 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1264
1265 psge = (char *)
1266 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1267
1268 /* request */
1269 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1270 MPI_SGE_FLAGS_END_OF_BUFFER |
1271 MPI_SGE_FLAGS_DIRECTION |
1272 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1273 flagsLength |= (req->data_len - 4);
1274
1275 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1276 req->data_len, PCI_DMA_BIDIRECTIONAL);
1277 if (!dma_addr_out)
1278 goto put_mf;
1279 mpt_add_sge(psge, flagsLength, dma_addr_out);
1280 psge += (sizeof(u32) + sizeof(dma_addr_t));
1281
1282 /* response */
1283 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1284 flagsLength |= rsp->data_len + 4;
1285 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1286 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1287 if (!dma_addr_in)
1288 goto unmap;
1289 mpt_add_sge(psge, flagsLength, dma_addr_in);
1290
1291 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1292
1293 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1294 if (!timeleft) {
1295 printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
1296 /* On timeout reset the board */
1297 mpt_HardResetHandler(ioc, CAN_SLEEP);
1298 ret = -ETIMEDOUT;
1299 goto unmap;
1300 }
1301 mf = NULL;
1302
1303 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1304 SmpPassthroughReply_t *smprep;
1305
1306 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1307 memcpy(req->sense, smprep, sizeof(*smprep));
1308 req->sense_len = sizeof(*smprep);
1309 } else {
1310 printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
1311 __FUNCTION__);
1312 ret = -ENXIO;
1313 }
1314unmap:
1315 if (dma_addr_out)
1316 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1317 PCI_DMA_BIDIRECTIONAL);
1318 if (dma_addr_in)
1319 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1320 PCI_DMA_BIDIRECTIONAL);
1321put_mf:
1322 if (mf)
1323 mpt_free_msg_frame(ioc, mf);
1324out_unlock:
1325 mutex_unlock(&ioc->sas_mgmt.mutex);
1326out:
1327 return ret;
1328}
1329
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001330static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001331 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001332 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1333 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001334 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001335 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001336};
1337
1338static struct scsi_transport_template *mptsas_transport_template;
1339
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001340static int
1341mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1342{
1343 ConfigExtendedPageHeader_t hdr;
1344 CONFIGPARMS cfg;
1345 SasIOUnitPage0_t *buffer;
1346 dma_addr_t dma_handle;
1347 int error, i;
1348
1349 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1350 hdr.ExtPageLength = 0;
1351 hdr.PageNumber = 0;
1352 hdr.Reserved1 = 0;
1353 hdr.Reserved2 = 0;
1354 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1355 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1356
1357 cfg.cfghdr.ehdr = &hdr;
1358 cfg.physAddr = -1;
1359 cfg.pageAddr = 0;
1360 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1361 cfg.dir = 0; /* read */
1362 cfg.timeout = 10;
1363
1364 error = mpt_config(ioc, &cfg);
1365 if (error)
1366 goto out;
1367 if (!hdr.ExtPageLength) {
1368 error = -ENXIO;
1369 goto out;
1370 }
1371
1372 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1373 &dma_handle);
1374 if (!buffer) {
1375 error = -ENOMEM;
1376 goto out;
1377 }
1378
1379 cfg.physAddr = dma_handle;
1380 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1381
1382 error = mpt_config(ioc, &cfg);
1383 if (error)
1384 goto out_free_consistent;
1385
1386 port_info->num_phys = buffer->NumPhys;
1387 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001388 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001389 if (!port_info->phy_info) {
1390 error = -ENOMEM;
1391 goto out_free_consistent;
1392 }
1393
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301394 ioc->nvdata_version_persistent =
1395 le16_to_cpu(buffer->NvdataVersionPersistent);
1396 ioc->nvdata_version_default =
1397 le16_to_cpu(buffer->NvdataVersionDefault);
1398
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001399 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301400 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001401 port_info->phy_info[i].phy_id = i;
1402 port_info->phy_info[i].port_id =
1403 buffer->PhyData[i].Port;
1404 port_info->phy_info[i].negotiated_link_rate =
1405 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001406 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001407 port_info->phy_info[i].handle =
1408 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001409 }
1410
1411 out_free_consistent:
1412 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1413 buffer, dma_handle);
1414 out:
1415 return error;
1416}
1417
1418static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301419mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1420{
1421 ConfigExtendedPageHeader_t hdr;
1422 CONFIGPARMS cfg;
1423 SasIOUnitPage1_t *buffer;
1424 dma_addr_t dma_handle;
1425 int error;
1426 u16 device_missing_delay;
1427
1428 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1429 memset(&cfg, 0, sizeof(CONFIGPARMS));
1430
1431 cfg.cfghdr.ehdr = &hdr;
1432 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1433 cfg.timeout = 10;
1434 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1435 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1436 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1437 cfg.cfghdr.ehdr->PageNumber = 1;
1438
1439 error = mpt_config(ioc, &cfg);
1440 if (error)
1441 goto out;
1442 if (!hdr.ExtPageLength) {
1443 error = -ENXIO;
1444 goto out;
1445 }
1446
1447 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1448 &dma_handle);
1449 if (!buffer) {
1450 error = -ENOMEM;
1451 goto out;
1452 }
1453
1454 cfg.physAddr = dma_handle;
1455 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1456
1457 error = mpt_config(ioc, &cfg);
1458 if (error)
1459 goto out_free_consistent;
1460
1461 ioc->io_missing_delay =
1462 le16_to_cpu(buffer->IODeviceMissingDelay);
1463 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1464 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1465 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1466 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1467
1468 out_free_consistent:
1469 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1470 buffer, dma_handle);
1471 out:
1472 return error;
1473}
1474
1475static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001476mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1477 u32 form, u32 form_specific)
1478{
1479 ConfigExtendedPageHeader_t hdr;
1480 CONFIGPARMS cfg;
1481 SasPhyPage0_t *buffer;
1482 dma_addr_t dma_handle;
1483 int error;
1484
1485 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1486 hdr.ExtPageLength = 0;
1487 hdr.PageNumber = 0;
1488 hdr.Reserved1 = 0;
1489 hdr.Reserved2 = 0;
1490 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1491 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1492
1493 cfg.cfghdr.ehdr = &hdr;
1494 cfg.dir = 0; /* read */
1495 cfg.timeout = 10;
1496
1497 /* Get Phy Pg 0 for each Phy. */
1498 cfg.physAddr = -1;
1499 cfg.pageAddr = form + form_specific;
1500 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1501
1502 error = mpt_config(ioc, &cfg);
1503 if (error)
1504 goto out;
1505
1506 if (!hdr.ExtPageLength) {
1507 error = -ENXIO;
1508 goto out;
1509 }
1510
1511 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1512 &dma_handle);
1513 if (!buffer) {
1514 error = -ENOMEM;
1515 goto out;
1516 }
1517
1518 cfg.physAddr = dma_handle;
1519 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1520
1521 error = mpt_config(ioc, &cfg);
1522 if (error)
1523 goto out_free_consistent;
1524
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301525 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001526
1527 phy_info->hw_link_rate = buffer->HwLinkRate;
1528 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1529 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1530 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1531
1532 out_free_consistent:
1533 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1534 buffer, dma_handle);
1535 out:
1536 return error;
1537}
1538
1539static int
1540mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1541 u32 form, u32 form_specific)
1542{
1543 ConfigExtendedPageHeader_t hdr;
1544 CONFIGPARMS cfg;
1545 SasDevicePage0_t *buffer;
1546 dma_addr_t dma_handle;
1547 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001548 int error=0;
1549
1550 if (ioc->sas_discovery_runtime &&
1551 mptsas_is_end_device(device_info))
1552 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001553
1554 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1555 hdr.ExtPageLength = 0;
1556 hdr.PageNumber = 0;
1557 hdr.Reserved1 = 0;
1558 hdr.Reserved2 = 0;
1559 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1560 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1561
1562 cfg.cfghdr.ehdr = &hdr;
1563 cfg.pageAddr = form + form_specific;
1564 cfg.physAddr = -1;
1565 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1566 cfg.dir = 0; /* read */
1567 cfg.timeout = 10;
1568
Moore, Ericdb9c9172006-03-14 09:14:18 -07001569 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001570 error = mpt_config(ioc, &cfg);
1571 if (error)
1572 goto out;
1573 if (!hdr.ExtPageLength) {
1574 error = -ENXIO;
1575 goto out;
1576 }
1577
1578 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1579 &dma_handle);
1580 if (!buffer) {
1581 error = -ENOMEM;
1582 goto out;
1583 }
1584
1585 cfg.physAddr = dma_handle;
1586 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1587
1588 error = mpt_config(ioc, &cfg);
1589 if (error)
1590 goto out_free_consistent;
1591
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301592 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001593
1594 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001595 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001596 device_info->handle_enclosure =
1597 le16_to_cpu(buffer->EnclosureHandle);
1598 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001599 device_info->phy_id = buffer->PhyNum;
1600 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001601 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001602 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001603 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001604 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1605 device_info->sas_address = le64_to_cpu(sas_address);
1606 device_info->device_info =
1607 le32_to_cpu(buffer->DeviceInfo);
1608
1609 out_free_consistent:
1610 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1611 buffer, dma_handle);
1612 out:
1613 return error;
1614}
1615
1616static int
1617mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1618 u32 form, u32 form_specific)
1619{
1620 ConfigExtendedPageHeader_t hdr;
1621 CONFIGPARMS cfg;
1622 SasExpanderPage0_t *buffer;
1623 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001624 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001625
1626 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1627 hdr.ExtPageLength = 0;
1628 hdr.PageNumber = 0;
1629 hdr.Reserved1 = 0;
1630 hdr.Reserved2 = 0;
1631 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1632 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1633
1634 cfg.cfghdr.ehdr = &hdr;
1635 cfg.physAddr = -1;
1636 cfg.pageAddr = form + form_specific;
1637 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1638 cfg.dir = 0; /* read */
1639 cfg.timeout = 10;
1640
Moore, Ericdb9c9172006-03-14 09:14:18 -07001641 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001642 error = mpt_config(ioc, &cfg);
1643 if (error)
1644 goto out;
1645
1646 if (!hdr.ExtPageLength) {
1647 error = -ENXIO;
1648 goto out;
1649 }
1650
1651 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1652 &dma_handle);
1653 if (!buffer) {
1654 error = -ENOMEM;
1655 goto out;
1656 }
1657
1658 cfg.physAddr = dma_handle;
1659 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1660
1661 error = mpt_config(ioc, &cfg);
1662 if (error)
1663 goto out_free_consistent;
1664
1665 /* save config data */
1666 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001667 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001668 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001669 if (!port_info->phy_info) {
1670 error = -ENOMEM;
1671 goto out_free_consistent;
1672 }
1673
Eric Moore2ecce492007-01-29 09:47:08 -07001674 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001675 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001676 port_info->phy_info[i].handle =
1677 le16_to_cpu(buffer->DevHandle);
1678 }
Eric Moore547f9a22006-06-27 14:42:12 -06001679
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001680 out_free_consistent:
1681 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1682 buffer, dma_handle);
1683 out:
1684 return error;
1685}
1686
1687static int
1688mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1689 u32 form, u32 form_specific)
1690{
1691 ConfigExtendedPageHeader_t hdr;
1692 CONFIGPARMS cfg;
1693 SasExpanderPage1_t *buffer;
1694 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001695 int error=0;
1696
1697 if (ioc->sas_discovery_runtime &&
1698 mptsas_is_end_device(&phy_info->attached))
1699 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001700
1701 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1702 hdr.ExtPageLength = 0;
1703 hdr.PageNumber = 1;
1704 hdr.Reserved1 = 0;
1705 hdr.Reserved2 = 0;
1706 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1707 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1708
1709 cfg.cfghdr.ehdr = &hdr;
1710 cfg.physAddr = -1;
1711 cfg.pageAddr = form + form_specific;
1712 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1713 cfg.dir = 0; /* read */
1714 cfg.timeout = 10;
1715
1716 error = mpt_config(ioc, &cfg);
1717 if (error)
1718 goto out;
1719
1720 if (!hdr.ExtPageLength) {
1721 error = -ENXIO;
1722 goto out;
1723 }
1724
1725 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1726 &dma_handle);
1727 if (!buffer) {
1728 error = -ENOMEM;
1729 goto out;
1730 }
1731
1732 cfg.physAddr = dma_handle;
1733 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1734
1735 error = mpt_config(ioc, &cfg);
1736 if (error)
1737 goto out_free_consistent;
1738
1739
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301740 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001741
1742 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001743 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001744 phy_info->port_id = buffer->PhysicalPort;
1745 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1746 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1747 phy_info->hw_link_rate = buffer->HwLinkRate;
1748 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1749 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1750
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001751 out_free_consistent:
1752 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1753 buffer, dma_handle);
1754 out:
1755 return error;
1756}
1757
1758static void
1759mptsas_parse_device_info(struct sas_identify *identify,
1760 struct mptsas_devinfo *device_info)
1761{
1762 u16 protocols;
1763
1764 identify->sas_address = device_info->sas_address;
1765 identify->phy_identifier = device_info->phy_id;
1766
1767 /*
1768 * Fill in Phy Initiator Port Protocol.
1769 * Bits 6:3, more than one bit can be set, fall through cases.
1770 */
1771 protocols = device_info->device_info & 0x78;
1772 identify->initiator_port_protocols = 0;
1773 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1774 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1775 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1776 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1777 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1778 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1779 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1780 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1781
1782 /*
1783 * Fill in Phy Target Port Protocol.
1784 * Bits 10:7, more than one bit can be set, fall through cases.
1785 */
1786 protocols = device_info->device_info & 0x780;
1787 identify->target_port_protocols = 0;
1788 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1789 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1790 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1791 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1792 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1793 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1794 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1795 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1796
1797 /*
1798 * Fill in Attached device type.
1799 */
1800 switch (device_info->device_info &
1801 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1802 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1803 identify->device_type = SAS_PHY_UNUSED;
1804 break;
1805 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1806 identify->device_type = SAS_END_DEVICE;
1807 break;
1808 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1809 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1810 break;
1811 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1812 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1813 break;
1814 }
1815}
1816
1817static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001818 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001819{
Moore, Erice6b2d762006-03-14 09:14:24 -07001820 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001821 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001822 struct sas_port *port;
1823 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moore547f9a22006-06-27 14:42:12 -06001825 if (!dev) {
1826 error = -ENODEV;
1827 goto out;
1828 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001829
1830 if (!phy_info->phy) {
1831 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001832 if (!phy) {
1833 error = -ENOMEM;
1834 goto out;
1835 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001836 } else
1837 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001839 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840
1841 /*
1842 * Set Negotiated link rate.
1843 */
1844 switch (phy_info->negotiated_link_rate) {
1845 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001846 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001847 break;
1848 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001849 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001850 break;
1851 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001852 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853 break;
1854 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001855 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001856 break;
1857 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1858 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1859 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001860 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001861 break;
1862 }
1863
1864 /*
1865 * Set Max hardware link rate.
1866 */
1867 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1868 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001869 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001870 break;
1871 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001872 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001873 break;
1874 default:
1875 break;
1876 }
1877
1878 /*
1879 * Set Max programmed link rate.
1880 */
1881 switch (phy_info->programmed_link_rate &
1882 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1883 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001884 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 break;
1886 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001887 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 break;
1889 default:
1890 break;
1891 }
1892
1893 /*
1894 * Set Min hardware link rate.
1895 */
1896 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1897 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001898 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001899 break;
1900 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001901 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001902 break;
1903 default:
1904 break;
1905 }
1906
1907 /*
1908 * Set Min programmed link rate.
1909 */
1910 switch (phy_info->programmed_link_rate &
1911 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1912 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001913 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001914 break;
1915 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001916 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001917 break;
1918 default:
1919 break;
1920 }
1921
Moore, Erice6b2d762006-03-14 09:14:24 -07001922 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001923
Moore, Erice6b2d762006-03-14 09:14:24 -07001924 error = sas_phy_add(phy);
1925 if (error) {
1926 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001927 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001928 }
1929 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001930 }
1931
Eric Moore547f9a22006-06-27 14:42:12 -06001932 if (!phy_info->attached.handle ||
1933 !phy_info->port_details)
1934 goto out;
1935
1936 port = mptsas_get_port(phy_info);
1937 ioc = phy_to_ioc(phy_info->phy);
1938
1939 if (phy_info->sas_port_add_phy) {
1940
1941 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001942 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001943 if (!port) {
1944 error = -ENOMEM;
1945 goto out;
1946 }
1947 error = sas_port_add(port);
1948 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301949 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001950 "%s: exit at line=%d\n", ioc->name,
1951 __FUNCTION__, __LINE__));
1952 goto out;
1953 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301954 mptsas_set_port(ioc, phy_info, port);
1955 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -06001956 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1957 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001958 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301959 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
Eric Moore547f9a22006-06-27 14:42:12 -06001960 phy_info->phy_id));
1961 sas_port_add_phy(port, phy_info->phy);
1962 phy_info->sas_port_add_phy = 0;
1963 }
1964
1965 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001966
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001967 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001968 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001969 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001970
James Bottomley2686de22006-06-30 12:54:02 -05001971 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001972 /*
1973 * Let the hotplug_work thread handle processing
1974 * the adding/removing of devices that occur
1975 * after start of day.
1976 */
1977 if (ioc->sas_discovery_runtime &&
1978 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001979 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001980
James Bottomleyf013db32006-03-18 14:54:36 -06001981 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001982 if (scsi_is_host_device(parent)) {
1983 struct mptsas_portinfo *port_info;
1984 int i;
1985
1986 mutex_lock(&ioc->sas_topology_mutex);
1987 port_info = mptsas_find_portinfo_by_handle(ioc,
1988 ioc->handle);
1989 mutex_unlock(&ioc->sas_topology_mutex);
1990
1991 for (i = 0; i < port_info->num_phys; i++)
1992 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001993 identify.sas_address) {
1994 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001995 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001996 }
James Bottomley2686de22006-06-30 12:54:02 -05001997
1998 } else if (scsi_is_sas_rphy(parent)) {
1999 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2000 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002001 parent_rphy->identify.sas_address) {
2002 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002003 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002004 }
James Bottomley2686de22006-06-30 12:54:02 -05002005 }
2006
James Bottomleyf013db32006-03-18 14:54:36 -06002007 switch (identify.device_type) {
2008 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002009 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002010 break;
2011 case SAS_EDGE_EXPANDER_DEVICE:
2012 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002013 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002014 break;
2015 default:
2016 rphy = NULL;
2017 break;
2018 }
Eric Moore547f9a22006-06-27 14:42:12 -06002019 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302020 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002021 "%s: exit at line=%d\n", ioc->name,
2022 __FUNCTION__, __LINE__));
2023 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002024 }
2025
Eric Moore547f9a22006-06-27 14:42:12 -06002026 rphy->identify = identify;
2027 error = sas_rphy_add(rphy);
2028 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302029 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002030 "%s: exit at line=%d\n", ioc->name,
2031 __FUNCTION__, __LINE__));
2032 sas_rphy_free(rphy);
2033 goto out;
2034 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302035 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002036 }
2037
Eric Moore547f9a22006-06-27 14:42:12 -06002038 out:
2039 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002040}
2041
2042static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002043mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002044{
Moore, Erice6b2d762006-03-14 09:14:24 -07002045 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002046 int error = -ENOMEM, i;
2047
Moore, Erice6b2d762006-03-14 09:14:24 -07002048 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2049 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002050 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002051
Moore, Erice6b2d762006-03-14 09:14:24 -07002052 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002053 if (error)
2054 goto out_free_port_info;
2055
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302056 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002057 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002058 ioc->handle = hba->phy_info[0].handle;
2059 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002060 if (!port_info) {
2061 port_info = hba;
2062 list_add_tail(&port_info->list, &ioc->sas_topology);
2063 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002064 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002065 port_info->phy_info[i].negotiated_link_rate =
2066 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002067 port_info->phy_info[i].handle =
2068 hba->phy_info[i].handle;
2069 port_info->phy_info[i].port_id =
2070 hba->phy_info[i].port_id;
2071 }
Eric Moore547f9a22006-06-27 14:42:12 -06002072 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002073 kfree(hba);
2074 hba = NULL;
2075 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002076 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002077 for (i = 0; i < port_info->num_phys; i++) {
2078 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2079 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2080 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2081
2082 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002083 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2084 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2085 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002086 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002087 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002088 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002089 mptsas_sas_device_pg0(ioc,
2090 &port_info->phy_info[i].attached,
2091 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2092 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2093 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002094 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002095
Eric Moore547f9a22006-06-27 14:42:12 -06002096 mptsas_setup_wide_ports(ioc, port_info);
2097
2098 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002099 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002100 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002101
2102 return 0;
2103
2104 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002105 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002106 out:
2107 return error;
2108}
2109
2110static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002111mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002112{
Moore, Erice6b2d762006-03-14 09:14:24 -07002113 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002114 struct device *parent;
2115 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002116 int error = -ENOMEM, i, j;
2117
Moore, Erice6b2d762006-03-14 09:14:24 -07002118 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2119 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002120 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002121
Moore, Erice6b2d762006-03-14 09:14:24 -07002122 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002123 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2124 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002125 if (error)
2126 goto out_free_port_info;
2127
Eric Moore2ecce492007-01-29 09:47:08 -07002128 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002129
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002130 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002131 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2132 if (!port_info) {
2133 port_info = ex;
2134 list_add_tail(&port_info->list, &ioc->sas_topology);
2135 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002136 for (i = 0; i < ex->num_phys; i++) {
2137 port_info->phy_info[i].handle =
2138 ex->phy_info[i].handle;
2139 port_info->phy_info[i].port_id =
2140 ex->phy_info[i].port_id;
2141 }
Eric Moore547f9a22006-06-27 14:42:12 -06002142 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002143 kfree(ex);
2144 ex = NULL;
2145 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002146 mutex_unlock(&ioc->sas_topology_mutex);
2147
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002148 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002149 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2150 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2151 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2152
2153 if (port_info->phy_info[i].identify.handle) {
2154 mptsas_sas_device_pg0(ioc,
2155 &port_info->phy_info[i].identify,
2156 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2157 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2158 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002159 port_info->phy_info[i].identify.phy_id =
2160 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002161 }
2162
2163 if (port_info->phy_info[i].attached.handle) {
2164 mptsas_sas_device_pg0(ioc,
2165 &port_info->phy_info[i].attached,
2166 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2167 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2168 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002169 port_info->phy_info[i].attached.phy_id =
2170 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002171 }
Eric Moore547f9a22006-06-27 14:42:12 -06002172 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002173
Eric Moore547f9a22006-06-27 14:42:12 -06002174 parent = &ioc->sh->shost_gendev;
2175 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002176 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002177 list_for_each_entry(p, &ioc->sas_topology, list) {
2178 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002179 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002180 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002181 continue;
2182 rphy = mptsas_get_rphy(&p->phy_info[j]);
2183 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002184 }
2185 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002186 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002187 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002188
Eric Moore547f9a22006-06-27 14:42:12 -06002189 mptsas_setup_wide_ports(ioc, port_info);
2190
2191 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002192 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002193 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002194
2195 return 0;
2196
2197 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002198 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002199 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002200 kfree(ex);
2201 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002202 out:
2203 return error;
2204}
2205
Moore, Erice6b2d762006-03-14 09:14:24 -07002206/*
2207 * mptsas_delete_expander_phys
2208 *
2209 *
2210 * This will traverse topology, and remove expanders
2211 * that are no longer present
2212 */
2213static void
2214mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2215{
2216 struct mptsas_portinfo buffer;
2217 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002218 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002219 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002220 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002221 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002222
2223 mutex_lock(&ioc->sas_topology_mutex);
2224 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2225
2226 if (port_info->phy_info &&
2227 (!(port_info->phy_info[0].identify.device_info &
2228 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2229 continue;
2230
2231 if (mptsas_sas_expander_pg0(ioc, &buffer,
2232 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002233 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2234 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002235
2236 /*
2237 * Obtain the port_info instance to the parent port
2238 */
2239 parent = mptsas_find_portinfo_by_handle(ioc,
2240 port_info->phy_info[0].identify.handle_parent);
2241
2242 if (!parent)
2243 goto next_port;
2244
Eric Moore547f9a22006-06-27 14:42:12 -06002245 expander_sas_address =
2246 port_info->phy_info[0].identify.sas_address;
2247
Moore, Erice6b2d762006-03-14 09:14:24 -07002248 /*
2249 * Delete rphys in the parent that point
2250 * to this expander. The transport layer will
2251 * cleanup all the children.
2252 */
Eric Moore547f9a22006-06-27 14:42:12 -06002253 phy_info = parent->phy_info;
2254 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2255 port = mptsas_get_port(phy_info);
2256 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002257 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002258 if (phy_info->attached.sas_address !=
2259 expander_sas_address)
2260 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302261 dsaswideprintk(ioc,
2262 dev_printk(KERN_DEBUG, &port->dev,
2263 "delete port (%d)\n", port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002264 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302265 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002266 }
2267 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002268
2269 phy_info = port_info->phy_info;
2270 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302271 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002272
Moore, Erice6b2d762006-03-14 09:14:24 -07002273 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002274 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002275 kfree(port_info);
2276 }
2277 /*
2278 * Free this memory allocated from inside
2279 * mptsas_sas_expander_pg0
2280 */
Eric Moore547f9a22006-06-27 14:42:12 -06002281 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002282 }
2283 mutex_unlock(&ioc->sas_topology_mutex);
2284}
2285
2286/*
2287 * Start of day discovery
2288 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002289static void
2290mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2291{
2292 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002293 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002294
Moore, Erice6b2d762006-03-14 09:14:24 -07002295 mutex_lock(&ioc->sas_discovery_mutex);
2296 mptsas_probe_hba_phys(ioc);
2297 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002298 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002299 /*
2300 Reporting RAID volumes.
2301 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002302 if (!ioc->ir_firmware)
2303 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002304 if (!ioc->raid_data.pIocPg2)
2305 goto out;
2306 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2307 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002308 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002309 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002310 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2311 }
2312 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002313 mutex_unlock(&ioc->sas_discovery_mutex);
2314}
2315
2316/*
2317 * Work queue thread to handle Runtime discovery
2318 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002319 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002320 */
2321static void
Eric Moore547f9a22006-06-27 14:42:12 -06002322__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002323{
Moore, Erice6b2d762006-03-14 09:14:24 -07002324 u32 handle = 0xFFFF;
2325
Moore, Erice6b2d762006-03-14 09:14:24 -07002326 ioc->sas_discovery_runtime=1;
2327 mptsas_delete_expander_phys(ioc);
2328 mptsas_probe_hba_phys(ioc);
2329 while (!mptsas_probe_expander_phys(ioc, &handle))
2330 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002331 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002332}
2333
2334/*
2335 * Work queue thread to handle Runtime discovery
2336 * Mere purpose is the hot add/delete of expanders
2337 *(Mutex LOCKED)
2338 */
2339static void
David Howellsc4028952006-11-22 14:57:56 +00002340mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002341{
David Howellsc4028952006-11-22 14:57:56 +00002342 struct mptsas_discovery_event *ev =
2343 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002344 MPT_ADAPTER *ioc = ev->ioc;
2345
2346 mutex_lock(&ioc->sas_discovery_mutex);
2347 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002348 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002349 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002350}
2351
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002352static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002353mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002354{
2355 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002356 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002357 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002358
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002359 mutex_lock(&ioc->sas_topology_mutex);
2360 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2361 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002362 if (!mptsas_is_end_device(
2363 &port_info->phy_info[i].attached))
2364 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002365 if (port_info->phy_info[i].attached.sas_address
2366 != sas_address)
2367 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002368 phy_info = &port_info->phy_info[i];
2369 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002370 }
2371 }
2372 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002373 return phy_info;
2374}
2375
2376static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002377mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002378{
2379 struct mptsas_portinfo *port_info;
2380 struct mptsas_phyinfo *phy_info = NULL;
2381 int i;
2382
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002383 mutex_lock(&ioc->sas_topology_mutex);
2384 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002385 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002386 if (!mptsas_is_end_device(
2387 &port_info->phy_info[i].attached))
2388 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002389 if (port_info->phy_info[i].attached.id != id)
2390 continue;
2391 if (port_info->phy_info[i].attached.channel != channel)
2392 continue;
2393 phy_info = &port_info->phy_info[i];
2394 break;
2395 }
2396 }
2397 mutex_unlock(&ioc->sas_topology_mutex);
2398 return phy_info;
2399}
2400
2401static struct mptsas_phyinfo *
2402mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2403{
2404 struct mptsas_portinfo *port_info;
2405 struct mptsas_phyinfo *phy_info = NULL;
2406 int i;
2407
2408 mutex_lock(&ioc->sas_topology_mutex);
2409 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2410 for (i = 0; i < port_info->num_phys; i++) {
2411 if (!mptsas_is_end_device(
2412 &port_info->phy_info[i].attached))
2413 continue;
2414 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2415 continue;
2416 if (port_info->phy_info[i].attached.phys_disk_num != id)
2417 continue;
2418 if (port_info->phy_info[i].attached.channel != channel)
2419 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002420 phy_info = &port_info->phy_info[i];
2421 break;
2422 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002423 }
2424 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002425 return phy_info;
2426}
2427
Moore, Eric4b766472006-03-14 09:14:12 -07002428/*
2429 * Work queue thread to clear the persitency table
2430 */
2431static void
David Howellsc4028952006-11-22 14:57:56 +00002432mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002433{
David Howellsc4028952006-11-22 14:57:56 +00002434 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002435
2436 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2437}
2438
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002439static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002440mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2441{
Eric Mooref99be432007-01-04 20:46:54 -07002442 int rc;
2443
Moore, Ericf44e5462006-03-14 09:14:21 -07002444 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002445 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002446}
2447
2448static void
2449mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2450{
2451 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2452 mptsas_reprobe_lun);
2453}
2454
Eric Mooreb506ade2007-01-29 09:45:37 -07002455static void
2456mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2457{
2458 CONFIGPARMS cfg;
2459 ConfigPageHeader_t hdr;
2460 dma_addr_t dma_handle;
2461 pRaidVolumePage0_t buffer = NULL;
2462 RaidPhysDiskPage0_t phys_disk;
2463 int i;
2464 struct mptsas_hotplug_event *ev;
2465
2466 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2467 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2468 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2469 cfg.pageAddr = (channel << 8) + id;
2470 cfg.cfghdr.hdr = &hdr;
2471 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2472
2473 if (mpt_config(ioc, &cfg) != 0)
2474 goto out;
2475
2476 if (!hdr.PageLength)
2477 goto out;
2478
2479 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2480 &dma_handle);
2481
2482 if (!buffer)
2483 goto out;
2484
2485 cfg.physAddr = dma_handle;
2486 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2487
2488 if (mpt_config(ioc, &cfg) != 0)
2489 goto out;
2490
2491 if (!(buffer->VolumeStatus.Flags &
2492 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2493 goto out;
2494
2495 if (!buffer->NumPhysDisks)
2496 goto out;
2497
2498 for (i = 0; i < buffer->NumPhysDisks; i++) {
2499
2500 if (mpt_raid_phys_disk_pg0(ioc,
2501 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2502 continue;
2503
2504 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2505 if (!ev) {
2506 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2507 goto out;
2508 }
2509
2510 INIT_WORK(&ev->work, mptsas_hotplug_work);
2511 ev->ioc = ioc;
2512 ev->id = phys_disk.PhysDiskID;
2513 ev->channel = phys_disk.PhysDiskBus;
2514 ev->phys_disk_num_valid = 1;
2515 ev->phys_disk_num = phys_disk.PhysDiskNum;
2516 ev->event_type = MPTSAS_ADD_DEVICE;
2517 schedule_work(&ev->work);
2518 }
2519
2520 out:
2521 if (buffer)
2522 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2523 dma_handle);
2524}
Moore, Erice6b2d762006-03-14 09:14:24 -07002525/*
2526 * Work queue thread to handle SAS hotplug events
2527 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002528static void
David Howellsc4028952006-11-22 14:57:56 +00002529mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002530{
David Howellsc4028952006-11-22 14:57:56 +00002531 struct mptsas_hotplug_event *ev =
2532 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002533
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002534 MPT_ADAPTER *ioc = ev->ioc;
2535 struct mptsas_phyinfo *phy_info;
2536 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002537 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002538 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002539 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002540 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002541 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002542 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002543 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002544 VirtDevice *vdevice;
2545
Moore, Erice6b2d762006-03-14 09:14:24 -07002546 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002547 switch (ev->event_type) {
2548 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002549
Eric Mooreb506ade2007-01-29 09:45:37 -07002550 phy_info = NULL;
2551 if (ev->phys_disk_num_valid) {
2552 if (ev->hidden_raid_component){
2553 if (mptsas_sas_device_pg0(ioc, &sas_device,
2554 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2555 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2556 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302557 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002558 "%s: exit at line=%d\n", ioc->name,
2559 __FUNCTION__, __LINE__));
2560 break;
2561 }
2562 phy_info = mptsas_find_phyinfo_by_sas_address(
2563 ioc, sas_device.sas_address);
2564 }else
2565 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2566 ioc, ev->channel, ev->phys_disk_num);
2567 }
2568
2569 if (!phy_info)
2570 phy_info = mptsas_find_phyinfo_by_target(ioc,
2571 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002572
Moore, Ericf44e5462006-03-14 09:14:21 -07002573 /*
2574 * Sanity checks, for non-existing phys and remote rphys.
2575 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002576 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302577 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002578 "%s: exit at line=%d\n", ioc->name,
2579 __FUNCTION__, __LINE__));
2580 break;
2581 }
2582 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302583 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002584 "%s: exit at line=%d\n", ioc->name,
2585 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002586 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002587 }
2588 rphy = mptsas_get_rphy(phy_info);
2589 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302590 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002591 "%s: exit at line=%d\n", ioc->name,
2592 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002593 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002594 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002595
Eric Moore547f9a22006-06-27 14:42:12 -06002596 port = mptsas_get_port(phy_info);
2597 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302598 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002599 "%s: exit at line=%d\n", ioc->name,
2600 __FUNCTION__, __LINE__));
2601 break;
2602 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002603
Eric Moore547f9a22006-06-27 14:42:12 -06002604 starget = mptsas_get_starget(phy_info);
2605 if (starget) {
2606 vtarget = starget->hostdata;
2607
2608 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302609 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002610 "%s: exit at line=%d\n", ioc->name,
2611 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002612 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002613 }
2614
Moore, Ericf44e5462006-03-14 09:14:21 -07002615 /*
2616 * Handling RAID components
2617 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002618 if (ev->phys_disk_num_valid &&
2619 ev->hidden_raid_component) {
2620 printk(MYIOC_s_INFO_FMT
2621 "RAID Hidding: channel=%d, id=%d, "
2622 "physdsk %d \n", ioc->name, ev->channel,
2623 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002624 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002625 vtarget->tflags |=
2626 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002627 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002628 phy_info->attached.phys_disk_num =
2629 ev->phys_disk_num;
2630 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002631 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002632 }
2633
Eric Mooreb506ade2007-01-29 09:45:37 -07002634 if (phy_info->attached.device_info &
2635 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002636 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002637 if (phy_info->attached.device_info &
2638 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002639 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002640 if (phy_info->attached.device_info &
2641 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002642 ds = "sata";
2643
2644 printk(MYIOC_s_INFO_FMT
2645 "removing %s device, channel %d, id %d, phy %d\n",
2646 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Mooredc22f162006-07-06 11:23:14 -06002647 dev_printk(KERN_DEBUG, &port->dev,
2648 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002649 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302650 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002651 break;
2652 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002653
Moore, Ericbd23e942006-04-17 12:43:04 -06002654 if (ev->phys_disk_num_valid)
2655 mpt_findImVolumes(ioc);
2656
Moore, Ericc73787ee2006-01-26 16:20:06 -07002657 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002658 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002659 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002660 if (mptsas_sas_device_pg0(ioc, &sas_device,
2661 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002662 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2663 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302664 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002665 "%s: exit at line=%d\n", ioc->name,
2666 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002667 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002668 }
2669
Eric Moore547f9a22006-06-27 14:42:12 -06002670 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002671
Eric Moore547f9a22006-06-27 14:42:12 -06002672 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2673 sas_device.sas_address);
2674
2675 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302676 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002677 "%s: exit at line=%d\n", ioc->name,
2678 __FUNCTION__, __LINE__));
2679 break;
2680 }
2681
2682 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002683 if (starget && (!ev->hidden_raid_component)){
2684
Eric Moore547f9a22006-06-27 14:42:12 -06002685 vtarget = starget->hostdata;
2686
2687 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302688 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002689 "%s: exit at line=%d\n", ioc->name,
2690 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002691 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002692 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002693 /*
2694 * Handling RAID components
2695 */
2696 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002697 printk(MYIOC_s_INFO_FMT
2698 "RAID Exposing: channel=%d, id=%d, "
2699 "physdsk %d \n", ioc->name, ev->channel,
2700 ev->id, ev->phys_disk_num);
2701 vtarget->tflags &=
2702 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002703 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002704 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002705 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002706 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002707 break;
2708 }
2709
Eric Moore547f9a22006-06-27 14:42:12 -06002710 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302711 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002712 "%s: exit at line=%d\n", ioc->name,
2713 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002714 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002715 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002716 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002717
Eric Moore547f9a22006-06-27 14:42:12 -06002718 port = mptsas_get_port(phy_info);
2719 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302720 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002721 "%s: exit at line=%d\n", ioc->name,
2722 __FUNCTION__, __LINE__));
2723 break;
2724 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002725 memcpy(&phy_info->attached, &sas_device,
2726 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002727
Eric Mooreb506ade2007-01-29 09:45:37 -07002728 if (phy_info->attached.device_info &
2729 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002730 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002731 if (phy_info->attached.device_info &
2732 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002733 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002734 if (phy_info->attached.device_info &
2735 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002736 ds = "sata";
2737
2738 printk(MYIOC_s_INFO_FMT
2739 "attaching %s device, channel %d, id %d, phy %d\n",
2740 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2741
James Bottomleyf013db32006-03-18 14:54:36 -06002742 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002743 rphy = sas_end_device_alloc(port);
2744 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302745 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002746 "%s: exit at line=%d\n", ioc->name,
2747 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002748 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002749 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002750
James Bottomleyf013db32006-03-18 14:54:36 -06002751 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002752 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302753 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002754 "%s: exit at line=%d\n", ioc->name,
2755 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002756 sas_rphy_free(rphy);
2757 break;
2758 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302759 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002760 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002761 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002762 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2763 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002764 if (sdev) {
2765 scsi_device_put(sdev);
2766 break;
2767 }
2768 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002769 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002770 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2771 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002772 mpt_findImVolumes(ioc);
2773 break;
2774 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002775 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002776 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002777 if (!sdev)
2778 break;
2779 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002780 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002781 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002782 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002783 scsi_remove_device(sdev);
2784 scsi_device_put(sdev);
2785 mpt_findImVolumes(ioc);
2786 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002787 case MPTSAS_ADD_INACTIVE_VOLUME:
2788 mptsas_adding_inactive_raid_components(ioc,
2789 ev->channel, ev->id);
2790 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002791 case MPTSAS_IGNORE_EVENT:
2792 default:
2793 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002794 }
2795
Moore, Erice6b2d762006-03-14 09:14:24 -07002796 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002797 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002798}
2799
2800static void
Eric Moore547f9a22006-06-27 14:42:12 -06002801mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002802 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2803{
2804 struct mptsas_hotplug_event *ev;
2805 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2806 __le64 sas_address;
2807
2808 if ((device_info &
2809 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2810 MPI_SAS_DEVICE_INFO_STP_TARGET |
2811 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2812 return;
2813
Moore, Eric4b766472006-03-14 09:14:12 -07002814 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002815 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002816
2817 mptsas_target_reset_queue(ioc, sas_event_data);
2818 break;
2819
2820 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002821 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002822 if (!ev) {
2823 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2824 break;
2825 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002826
David Howellsc4028952006-11-22 14:57:56 +00002827 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002828 ev->ioc = ioc;
2829 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2830 ev->parent_handle =
2831 le16_to_cpu(sas_event_data->ParentDevHandle);
2832 ev->channel = sas_event_data->Bus;
2833 ev->id = sas_event_data->TargetID;
2834 ev->phy_id = sas_event_data->PhyNum;
2835 memcpy(&sas_address, &sas_event_data->SASAddress,
2836 sizeof(__le64));
2837 ev->sas_address = le64_to_cpu(sas_address);
2838 ev->device_info = device_info;
2839
2840 if (sas_event_data->ReasonCode &
2841 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2842 ev->event_type = MPTSAS_ADD_DEVICE;
2843 else
2844 ev->event_type = MPTSAS_DEL_DEVICE;
2845 schedule_work(&ev->work);
2846 break;
2847 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2848 /*
2849 * Persistent table is full.
2850 */
Eric Moore547f9a22006-06-27 14:42:12 -06002851 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002852 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002853 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002854 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002855 /*
2856 * TODO, handle other events
2857 */
Moore, Eric4b766472006-03-14 09:14:12 -07002858 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002859 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002860 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002861 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2862 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2863 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2864 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002865 default:
2866 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002867 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002868}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002869static void
Eric Moore547f9a22006-06-27 14:42:12 -06002870mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002871 EVENT_DATA_RAID *raid_event_data)
2872{
2873 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002874 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2875 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002876
2877 if (ioc->bus_type != SAS)
2878 return;
2879
Eric Moore547f9a22006-06-27 14:42:12 -06002880 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002881 if (!ev) {
2882 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2883 return;
2884 }
2885
David Howellsc4028952006-11-22 14:57:56 +00002886 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002887 ev->ioc = ioc;
2888 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002889 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002890 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002891
2892 switch (raid_event_data->ReasonCode) {
2893 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002894 ev->phys_disk_num_valid = 1;
2895 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002896 ev->event_type = MPTSAS_ADD_DEVICE;
2897 break;
2898 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002899 ev->phys_disk_num_valid = 1;
2900 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002901 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002902 ev->event_type = MPTSAS_DEL_DEVICE;
2903 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002904 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2905 switch (state) {
2906 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002907 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002908 ev->phys_disk_num_valid = 1;
2909 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002910 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002911 ev->event_type = MPTSAS_ADD_DEVICE;
2912 break;
2913 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002914 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2915 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2916 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002917 ev->phys_disk_num_valid = 1;
2918 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002919 ev->event_type = MPTSAS_DEL_DEVICE;
2920 break;
2921 default:
2922 break;
2923 }
2924 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002925 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2926 ev->event_type = MPTSAS_DEL_RAID;
2927 break;
2928 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2929 ev->event_type = MPTSAS_ADD_RAID;
2930 break;
2931 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002932 switch (state) {
2933 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2934 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2935 ev->event_type = MPTSAS_DEL_RAID;
2936 break;
2937 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2938 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2939 ev->event_type = MPTSAS_ADD_RAID;
2940 break;
2941 default:
2942 break;
2943 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002944 break;
2945 default:
2946 break;
2947 }
2948 schedule_work(&ev->work);
2949}
2950
Moore, Erice6b2d762006-03-14 09:14:24 -07002951static void
Eric Moore547f9a22006-06-27 14:42:12 -06002952mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002953 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2954{
2955 struct mptsas_discovery_event *ev;
2956
2957 /*
2958 * DiscoveryStatus
2959 *
2960 * This flag will be non-zero when firmware
2961 * kicks off discovery, and return to zero
2962 * once its completed.
2963 */
2964 if (discovery_data->DiscoveryStatus)
2965 return;
2966
Eric Moore547f9a22006-06-27 14:42:12 -06002967 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002968 if (!ev)
2969 return;
David Howellsc4028952006-11-22 14:57:56 +00002970 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002971 ev->ioc = ioc;
2972 schedule_work(&ev->work);
2973};
2974
Eric Mooreb506ade2007-01-29 09:45:37 -07002975/*
2976 * mptsas_send_ir2_event - handle exposing hidden disk when
2977 * an inactive raid volume is added
2978 *
2979 * @ioc: Pointer to MPT_ADAPTER structure
2980 * @ir2_data
2981 *
2982 */
2983static void
2984mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2985{
2986 struct mptsas_hotplug_event *ev;
2987
2988 if (ir2_data->ReasonCode !=
2989 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2990 return;
2991
2992 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2993 if (!ev)
2994 return;
2995
2996 INIT_WORK(&ev->work, mptsas_hotplug_work);
2997 ev->ioc = ioc;
2998 ev->id = ir2_data->TargetID;
2999 ev->channel = ir2_data->Bus;
3000 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3001
3002 schedule_work(&ev->work);
3003};
Moore, Erice6b2d762006-03-14 09:14:24 -07003004
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003005static int
3006mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3007{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003008 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003009 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3010
3011 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003012 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003013
Moore, Erice6b2d762006-03-14 09:14:24 -07003014 /*
3015 * sas_discovery_ignore_events
3016 *
3017 * This flag is to prevent anymore processing of
3018 * sas events once mptsas_remove function is called.
3019 */
3020 if (ioc->sas_discovery_ignore_events) {
3021 rc = mptscsih_event_process(ioc, reply);
3022 goto out;
3023 }
3024
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003025 switch (event) {
3026 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003027 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003028 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003029 break;
3030 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003031 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003032 (EVENT_DATA_RAID *)reply->Data);
3033 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003034 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003035 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003036 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003037 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003038 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003039 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003040 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003041 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3042 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003043 case MPI_EVENT_IR2:
3044 mptsas_send_ir2_event(ioc,
3045 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3046 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003047 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003048 rc = mptscsih_event_process(ioc, reply);
3049 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003050 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003051 out:
3052
3053 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003054}
3055
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003056static int
3057mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3058{
3059 struct Scsi_Host *sh;
3060 MPT_SCSI_HOST *hd;
3061 MPT_ADAPTER *ioc;
3062 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003063 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003064 int numSGE = 0;
3065 int scale;
3066 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003067 int error=0;
3068 int r;
3069
3070 r = mpt_attach(pdev,id);
3071 if (r)
3072 return r;
3073
3074 ioc = pci_get_drvdata(pdev);
3075 ioc->DoneCtx = mptsasDoneCtx;
3076 ioc->TaskCtx = mptsasTaskCtx;
3077 ioc->InternalCtx = mptsasInternalCtx;
3078
3079 /* Added sanity check on readiness of the MPT adapter.
3080 */
3081 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3082 printk(MYIOC_s_WARN_FMT
3083 "Skipping because it's not operational!\n",
3084 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003085 error = -ENODEV;
3086 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003087 }
3088
3089 if (!ioc->active) {
3090 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3091 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003092 error = -ENODEV;
3093 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003094 }
3095
3096 /* Sanity check - ensure at least 1 port is INITIATOR capable
3097 */
3098 ioc_cap = 0;
3099 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3100 if (ioc->pfacts[ii].ProtocolFlags &
3101 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3102 ioc_cap++;
3103 }
3104
3105 if (!ioc_cap) {
3106 printk(MYIOC_s_WARN_FMT
3107 "Skipping ioc=%p because SCSI Initiator mode "
3108 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003109 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003110 }
3111
3112 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3113 if (!sh) {
3114 printk(MYIOC_s_WARN_FMT
3115 "Unable to register controller with SCSI subsystem\n",
3116 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003117 error = -1;
3118 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003119 }
3120
3121 spin_lock_irqsave(&ioc->FreeQlock, flags);
3122
3123 /* Attach the SCSI Host to the IOC structure
3124 */
3125 ioc->sh = sh;
3126
3127 sh->io_port = 0;
3128 sh->n_io_port = 0;
3129 sh->irq = 0;
3130
3131 /* set 16 byte cdb's */
3132 sh->max_cmd_len = 16;
3133
Eric Moore793955f2007-01-29 09:42:20 -07003134 sh->max_id = ioc->pfacts[0].PortSCSIID;
3135 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003136
3137 sh->transportt = mptsas_transport_template;
3138
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003139 sh->this_id = ioc->pfacts[0].PortSCSIID;
3140
3141 /* Required entry.
3142 */
3143 sh->unique_id = ioc->id;
3144
3145 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003146 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003147 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003148 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003149 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003150
3151 /* Verify that we won't exceed the maximum
3152 * number of chain buffers
3153 * We can optimize: ZZ = req_sz/sizeof(SGE)
3154 * For 32bit SGE's:
3155 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3156 * + (req_sz - 64)/sizeof(SGE)
3157 * A slightly different algorithm is required for
3158 * 64bit SGEs.
3159 */
3160 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3161 if (sizeof(dma_addr_t) == sizeof(u64)) {
3162 numSGE = (scale - 1) *
3163 (ioc->facts.MaxChainDepth-1) + scale +
3164 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3165 sizeof(u32));
3166 } else {
3167 numSGE = 1 + (scale - 1) *
3168 (ioc->facts.MaxChainDepth-1) + scale +
3169 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3170 sizeof(u32));
3171 }
3172
3173 if (numSGE < sh->sg_tablesize) {
3174 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303175 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003176 "Resetting sg_tablesize to %d from %d\n",
3177 ioc->name, numSGE, sh->sg_tablesize));
3178 sh->sg_tablesize = numSGE;
3179 }
3180
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003181 hd = (MPT_SCSI_HOST *) sh->hostdata;
3182 hd->ioc = ioc;
3183
3184 /* SCSI needs scsi_cmnd lookup table!
3185 * (with size equal to req_depth*PtrSz!)
3186 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003187 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3188 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003189 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003190 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003191 }
3192
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303193 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003194 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003195
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003196 /* Clear the TM flags
3197 */
3198 hd->tmPending = 0;
3199 hd->tmState = TM_STATE_NONE;
3200 hd->resetPending = 0;
3201 hd->abortSCpnt = NULL;
3202
3203 /* Clear the pointer used to store
3204 * single-threaded commands, i.e., those
3205 * issued during a bus scan, dv and
3206 * configuration pages.
3207 */
3208 hd->cmdPtr = NULL;
3209
3210 /* Initialize this SCSI Hosts' timers
3211 * To use, set the timer expires field
3212 * and add_timer
3213 */
3214 init_timer(&hd->timer);
3215 hd->timer.data = (unsigned long) hd;
3216 hd->timer.function = mptscsih_timer_expired;
3217
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003218 ioc->sas_data.ptClear = mpt_pt_clear;
3219
Eric Mooredf9e0622007-01-29 09:46:21 -07003220 init_waitqueue_head(&hd->scandv_waitq);
3221 hd->scandv_wait_done = 0;
3222 hd->last_queue_full = 0;
3223 INIT_LIST_HEAD(&hd->target_reset_list);
3224 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3225
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003226 if (ioc->sas_data.ptClear==1) {
3227 mptbase_sas_persist_operation(
3228 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3229 }
3230
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003231 error = scsi_add_host(sh, &ioc->pcidev->dev);
3232 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303233 dprintk(ioc, printk(KERN_ERR MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003235 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003236 }
3237
3238 mptsas_scan_sas_topology(ioc);
3239
3240 return 0;
3241
Eric Moore547f9a22006-06-27 14:42:12 -06003242 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243
3244 mptscsih_remove(pdev);
3245 return error;
3246}
3247
3248static void __devexit mptsas_remove(struct pci_dev *pdev)
3249{
3250 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3251 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003252 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003253
Eric Mooreb506ade2007-01-29 09:45:37 -07003254 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003255 sas_remove_host(ioc->sh);
3256
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003257 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003258 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3259 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003260 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303261 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003262 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003263 kfree(p);
3264 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003265 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266
3267 mptscsih_remove(pdev);
3268}
3269
3270static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003271 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003272 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003273 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003274 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003275 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003277 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003279 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003280 PCI_ANY_ID, PCI_ANY_ID },
3281 {0} /* Terminating entry */
3282};
3283MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3284
3285
3286static struct pci_driver mptsas_driver = {
3287 .name = "mptsas",
3288 .id_table = mptsas_pci_table,
3289 .probe = mptsas_probe,
3290 .remove = __devexit_p(mptsas_remove),
3291 .shutdown = mptscsih_shutdown,
3292#ifdef CONFIG_PM
3293 .suspend = mptscsih_suspend,
3294 .resume = mptscsih_resume,
3295#endif
3296};
3297
3298static int __init
3299mptsas_init(void)
3300{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303301 int error;
3302
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003303 show_mptmod_ver(my_NAME, my_VERSION);
3304
3305 mptsas_transport_template =
3306 sas_attach_transport(&mptsas_transport_functions);
3307 if (!mptsas_transport_template)
3308 return -ENODEV;
3309
3310 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003311 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003312 mptsasInternalCtx =
3313 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003314 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003315
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303316 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3317 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003318
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303319 error = pci_register_driver(&mptsas_driver);
3320 if (error)
3321 sas_release_transport(mptsas_transport_template);
3322
3323 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003324}
3325
3326static void __exit
3327mptsas_exit(void)
3328{
3329 pci_unregister_driver(&mptsas_driver);
3330 sas_release_transport(mptsas_transport_template);
3331
3332 mpt_reset_deregister(mptsasDoneCtx);
3333 mpt_event_deregister(mptsasDoneCtx);
3334
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003335 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003336 mpt_deregister(mptsasInternalCtx);
3337 mpt_deregister(mptsasTaskCtx);
3338 mpt_deregister(mptsasDoneCtx);
3339}
3340
3341module_init(mptsas_init);
3342module_exit(mptsas_exit);