blob: ffbf0e59200e028011679a9535fa41ec3a7498bb [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic 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"
64
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Prakash, Sathyaf606f572007-08-14 16:12:53 +053092static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
93static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
95static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020096
Eric Mooreb506ade2007-01-29 09:45:37 -070097static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Eric Mooredf9e0622007-01-29 09:46:21 -070099struct mptsas_target_reset_event {
100 struct list_head list;
101 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
102 u8 target_reset_issued;
103};
104
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100105enum mptsas_hotplug_action {
106 MPTSAS_ADD_DEVICE,
107 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -0700108 MPTSAS_ADD_RAID,
109 MPTSAS_DEL_RAID,
Eric Mooreb506ade2007-01-29 09:45:37 -0700110 MPTSAS_ADD_INACTIVE_VOLUME,
Moore, Ericbd23e942006-04-17 12:43:04 -0600111 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100112};
113
114struct mptsas_hotplug_event {
115 struct work_struct work;
116 MPT_ADAPTER *ioc;
117 enum mptsas_hotplug_action event_type;
118 u64 sas_address;
Eric Mooreb506ade2007-01-29 09:45:37 -0700119 u8 channel;
120 u8 id;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100121 u32 device_info;
122 u16 handle;
123 u16 parent_handle;
124 u8 phy_id;
Eric Mooreb506ade2007-01-29 09:45:37 -0700125 u8 phys_disk_num_valid; /* hrc (hidden raid component) */
126 u8 phys_disk_num; /* hrc - unique index*/
127 u8 hidden_raid_component; /* hrc - don't expose*/
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100128};
129
Moore, Erice6b2d762006-03-14 09:14:24 -0700130struct mptsas_discovery_event {
131 struct work_struct work;
132 MPT_ADAPTER *ioc;
133};
134
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200135/*
136 * SAS topology structures
137 *
138 * The MPT Fusion firmware interface spreads information about the
139 * SAS topology over many manufacture pages, thus we need some data
140 * structure to collect it and process it for the SAS transport class.
141 */
142
143struct mptsas_devinfo {
144 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700145 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100146 u16 handle_enclosure; /* enclosure identifier of the enclosure */
147 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200148 u8 phy_id; /* phy number of parent device */
149 u8 port_id; /* sas physical port this device
150 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100151 u8 id; /* logical target id of this device */
Eric Mooreb506ade2007-01-29 09:45:37 -0700152 u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100153 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200154 u64 sas_address; /* WWN of this device,
155 SATA is assigned by HBA,expander */
156 u32 device_info; /* bitfield detailed info about this device */
157};
158
Eric Moore547f9a22006-06-27 14:42:12 -0600159/*
160 * Specific details on ports, wide/narrow
161 */
162struct mptsas_portinfo_details{
Eric Moore547f9a22006-06-27 14:42:12 -0600163 u16 num_phys; /* number of phys belong to this port */
164 u64 phy_bitmask; /* TODO, extend support for 255 phys */
165 struct sas_rphy *rphy; /* transport layer rphy object */
166 struct sas_port *port; /* transport layer port object */
167 struct scsi_target *starget;
168 struct mptsas_portinfo *port_info;
169};
170
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200171struct mptsas_phyinfo {
Eric Moore2ecce492007-01-29 09:47:08 -0700172 u16 handle; /* unique id to address this */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200173 u8 phy_id; /* phy index */
Eric Moore547f9a22006-06-27 14:42:12 -0600174 u8 port_id; /* firmware port identifier */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200175 u8 negotiated_link_rate; /* nego'd link rate for this phy */
176 u8 hw_link_rate; /* hardware max/min phys link rate */
177 u8 programmed_link_rate; /* programmed max/min phy link rate */
Eric Moore547f9a22006-06-27 14:42:12 -0600178 u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200179 struct mptsas_devinfo identify; /* point to phy device info */
180 struct mptsas_devinfo attached; /* point to attached device info */
Eric Moore547f9a22006-06-27 14:42:12 -0600181 struct sas_phy *phy; /* transport layer phy object */
182 struct mptsas_portinfo *portinfo;
183 struct mptsas_portinfo_details * port_details;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200184};
185
186struct mptsas_portinfo {
187 struct list_head list;
Eric Moore547f9a22006-06-27 14:42:12 -0600188 u16 num_phys; /* number of phys */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200189 struct mptsas_phyinfo *phy_info;
190};
191
Christoph Hellwige3094442006-02-16 13:25:36 +0100192struct mptsas_enclosure {
193 u64 enclosure_logical_id; /* The WWN for the enclosure */
194 u16 enclosure_handle; /* unique id to address this */
195 u16 flags; /* details enclosure management */
196 u16 num_slot; /* num slots */
197 u16 start_slot; /* first slot */
198 u8 start_id; /* starting logical target id */
199 u8 start_channel; /* starting logical channel id */
200 u8 sep_id; /* SEP device logical target id */
201 u8 sep_channel; /* SEP channel logical channel id */
202};
203
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530204static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
205 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200206{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530207 dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
208 dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
209 le16_to_cpu(phy_data->AttachedDeviceHandle)));
210 dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
211 le16_to_cpu(phy_data->ControllerDevHandle)));
212 dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
213 dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
214 dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
215 dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
216 dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
217 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
218 dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
219 le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200220}
221
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530222static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200223{
224 __le64 sas_address;
225
226 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
227
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530228 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
229 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
230 le16_to_cpu(pg0->AttachedDevHandle)));
231 dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
232 (unsigned long long)le64_to_cpu(sas_address)));
233 dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
234 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
235 le32_to_cpu(pg0->AttachedDeviceInfo)));
236 dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
237 dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
238 dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200239}
240
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530241static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200242{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530243 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
244 dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
245 dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
246 pg1->RunningDisparityErrorCount));
247 dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
248 dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200249}
250
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530251static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252{
253 __le64 sas_address;
254
255 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
256
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530257 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
258 dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
259 dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
260 dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
261 dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
262 dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
263 le64_to_cpu(sas_address)));
264 dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
265 dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200266 /* The PhyNum field specifies the PHY number of the parent
267 * device this device is linked to
268 */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530269 dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
270 dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
271 dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
272 dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
273 dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200274}
275
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530276static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200277{
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530278 dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
279 dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
280 dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
281 dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
282 dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
283 dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
284 dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
285 le16_to_cpu(pg1->OwnerDevHandle)));
286 dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
287 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200288}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200289
Christoph Hellwige3094442006-02-16 13:25:36 +0100290static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
291{
292 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
293 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
294}
295
296static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
297{
298 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
299 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
300}
301
Moore, Erice6b2d762006-03-14 09:14:24 -0700302/*
303 * mptsas_find_portinfo_by_handle
304 *
305 * This function should be called with the sas_topology_mutex already held
306 */
307static struct mptsas_portinfo *
308mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
309{
310 struct mptsas_portinfo *port_info, *rc=NULL;
311 int i;
312
313 list_for_each_entry(port_info, &ioc->sas_topology, list)
314 for (i = 0; i < port_info->num_phys; i++)
315 if (port_info->phy_info[i].identify.handle == handle) {
316 rc = port_info;
317 goto out;
318 }
319 out:
320 return rc;
321}
322
Moore, Ericbd23e942006-04-17 12:43:04 -0600323/*
324 * Returns true if there is a scsi end device
325 */
326static inline int
327mptsas_is_end_device(struct mptsas_devinfo * attached)
328{
Eric Moore547f9a22006-06-27 14:42:12 -0600329 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600330 (attached->device_info &
331 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
332 ((attached->device_info &
333 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
334 (attached->device_info &
335 MPI_SAS_DEVICE_INFO_STP_TARGET) |
336 (attached->device_info &
337 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
338 return 1;
339 else
340 return 0;
341}
342
Eric Moore547f9a22006-06-27 14:42:12 -0600343/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600344static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530345mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600346{
347 struct mptsas_portinfo *port_info;
348 struct mptsas_phyinfo *phy_info;
349 u8 i;
350
351 if (!port_details)
352 return;
353
354 port_info = port_details->port_info;
355 phy_info = port_info->phy_info;
356
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530357 dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700358 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
359 port_details->num_phys, (unsigned long long)
360 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600361
362 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
363 if(phy_info->port_details != port_details)
364 continue;
365 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
366 phy_info->port_details = NULL;
367 }
368 kfree(port_details);
369}
370
371static inline struct sas_rphy *
372mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
373{
374 if (phy_info->port_details)
375 return phy_info->port_details->rphy;
376 else
377 return NULL;
378}
379
380static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530381mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600382{
383 if (phy_info->port_details) {
384 phy_info->port_details->rphy = rphy;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530385 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600386 }
387
Eric Moore547f9a22006-06-27 14:42:12 -0600388 if (rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530389 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
390 &rphy->dev, "add:"));
391 dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
392 rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600393 }
Eric Moore547f9a22006-06-27 14:42:12 -0600394}
395
396static inline struct sas_port *
397mptsas_get_port(struct mptsas_phyinfo *phy_info)
398{
399 if (phy_info->port_details)
400 return phy_info->port_details->port;
401 else
402 return NULL;
403}
404
405static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530406mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600407{
408 if (phy_info->port_details)
409 phy_info->port_details->port = port;
410
Eric Moore547f9a22006-06-27 14:42:12 -0600411 if (port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530412 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
413 &port->dev, "add:"));
414 dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
415 port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600416 }
Eric Moore547f9a22006-06-27 14:42:12 -0600417}
418
419static inline struct scsi_target *
420mptsas_get_starget(struct mptsas_phyinfo *phy_info)
421{
422 if (phy_info->port_details)
423 return phy_info->port_details->starget;
424 else
425 return NULL;
426}
427
428static inline void
429mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
430starget)
431{
432 if (phy_info->port_details)
433 phy_info->port_details->starget = starget;
434}
435
436
437/*
438 * mptsas_setup_wide_ports
439 *
440 * Updates for new and existing narrow/wide port configuration
441 * in the sas_topology
442 */
Eric Moore376ac832006-06-29 17:36:26 -0600443static void
Eric Moore547f9a22006-06-27 14:42:12 -0600444mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
445{
446 struct mptsas_portinfo_details * port_details;
447 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
448 u64 sas_address;
449 int i, j;
450
451 mutex_lock(&ioc->sas_topology_mutex);
452
453 phy_info = port_info->phy_info;
454 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
455 if (phy_info->attached.handle)
456 continue;
457 port_details = phy_info->port_details;
458 if (!port_details)
459 continue;
460 if (port_details->num_phys < 2)
461 continue;
462 /*
463 * Removing a phy from a port, letting the last
464 * phy be removed by firmware events.
465 */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530466 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600467 "%s: [%p]: deleting phy = %d\n",
468 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600469 port_details->num_phys--;
470 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
471 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
472 sas_port_delete_phy(port_details->port, phy_info->phy);
473 phy_info->port_details = NULL;
474 }
475
476 /*
477 * Populate and refresh the tree
478 */
479 phy_info = port_info->phy_info;
480 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
481 sas_address = phy_info->attached.sas_address;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530482 dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700483 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600484 if (!sas_address)
485 continue;
486 port_details = phy_info->port_details;
487 /*
488 * Forming a port
489 */
490 if (!port_details) {
491 port_details = kzalloc(sizeof(*port_details),
492 GFP_KERNEL);
493 if (!port_details)
494 goto out;
495 port_details->num_phys = 1;
496 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600497 if (phy_info->phy_id < 64 )
498 port_details->phy_bitmask |=
499 (1 << phy_info->phy_id);
500 phy_info->sas_port_add_phy=1;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530501 dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700502 "phy_id=%d sas_address=0x%018llX\n",
503 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600504 phy_info->port_details = port_details;
505 }
506
507 if (i == port_info->num_phys - 1)
508 continue;
509 phy_info_cmp = &port_info->phy_info[i + 1];
510 for (j = i + 1 ; j < port_info->num_phys ; j++,
511 phy_info_cmp++) {
512 if (!phy_info_cmp->attached.sas_address)
513 continue;
514 if (sas_address != phy_info_cmp->attached.sas_address)
515 continue;
516 if (phy_info_cmp->port_details == port_details )
517 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530518 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700519 "\t\tphy_id=%d sas_address=0x%018llX\n",
520 j, (unsigned long long)
521 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600522 if (phy_info_cmp->port_details) {
523 port_details->rphy =
524 mptsas_get_rphy(phy_info_cmp);
525 port_details->port =
526 mptsas_get_port(phy_info_cmp);
527 port_details->starget =
528 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600529 port_details->num_phys =
530 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600531 if (!phy_info_cmp->port_details->num_phys)
532 kfree(phy_info_cmp->port_details);
533 } else
534 phy_info_cmp->sas_port_add_phy=1;
535 /*
536 * Adding a phy to a port
537 */
538 phy_info_cmp->port_details = port_details;
539 if (phy_info_cmp->phy_id < 64 )
540 port_details->phy_bitmask |=
541 (1 << phy_info_cmp->phy_id);
542 port_details->num_phys++;
543 }
544 }
545
546 out:
547
Eric Moore547f9a22006-06-27 14:42:12 -0600548 for (i = 0; i < port_info->num_phys; i++) {
549 port_details = port_info->phy_info[i].port_details;
550 if (!port_details)
551 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530552 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700553 "%s: [%p]: phy_id=%02d num_phys=%02d "
554 "bitmask=0x%016llX\n", __FUNCTION__,
555 port_details, i, port_details->num_phys,
556 (unsigned long long)port_details->phy_bitmask));
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530557 dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
Eric Moore547f9a22006-06-27 14:42:12 -0600558 port_details->port, port_details->rphy));
559 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530560 dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600561 mutex_unlock(&ioc->sas_topology_mutex);
562}
563
Eric Mooredf9e0622007-01-29 09:46:21 -0700564/**
565 * csmisas_find_vtarget
566 *
567 * @ioc
568 * @volume_id
569 * @volume_bus
570 *
571 **/
572static VirtTarget *
573mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600574{
Eric Mooredf9e0622007-01-29 09:46:21 -0700575 struct scsi_device *sdev;
576 VirtDevice *vdev;
577 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600578
Eric Mooredf9e0622007-01-29 09:46:21 -0700579 shost_for_each_device(sdev, ioc->sh) {
580 if ((vdev = sdev->hostdata) == NULL)
581 continue;
582 if (vdev->vtarget->id == id &&
583 vdev->vtarget->channel == channel)
584 vtarget = vdev->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600585 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700586 return vtarget;
587}
588
589/**
590 * mptsas_target_reset
591 *
592 * Issues TARGET_RESET to end device using handshaking method
593 *
594 * @ioc
595 * @channel
596 * @id
597 *
598 * Returns (1) success
599 * (0) failure
600 *
601 **/
602static int
603mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
604{
605 MPT_FRAME_HDR *mf;
606 SCSITaskMgmt_t *pScsiTm;
607
608 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530609 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700610 ioc->name,__FUNCTION__, __LINE__));
611 return 0;
612 }
613
614 /* Format the Request
615 */
616 pScsiTm = (SCSITaskMgmt_t *) mf;
617 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
618 pScsiTm->TargetID = id;
619 pScsiTm->Bus = channel;
620 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
621 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
622 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
623
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530624 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700625
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530626 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700627
628 return 1;
629}
630
631/**
632 * mptsas_target_reset_queue
633 *
634 * Receive request for TARGET_RESET after recieving an firmware
635 * event NOT_RESPONDING_EVENT, then put command in link list
636 * and queue if task_queue already in use.
637 *
638 * @ioc
639 * @sas_event_data
640 *
641 **/
642static void
643mptsas_target_reset_queue(MPT_ADAPTER *ioc,
644 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
645{
646 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
647 VirtTarget *vtarget = NULL;
648 struct mptsas_target_reset_event *target_reset_list;
649 u8 id, channel;
650
651 id = sas_event_data->TargetID;
652 channel = sas_event_data->Bus;
653
654 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
655 return;
656
657 vtarget->deleted = 1; /* block IO */
658
659 target_reset_list = kzalloc(sizeof(*target_reset_list),
660 GFP_ATOMIC);
661 if (!target_reset_list) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530662 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700663 ioc->name,__FUNCTION__, __LINE__));
664 return;
665 }
666
667 memcpy(&target_reset_list->sas_event_data, sas_event_data,
668 sizeof(*sas_event_data));
669 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
670
671 if (hd->resetPending)
672 return;
673
674 if (mptsas_target_reset(ioc, channel, id)) {
675 target_reset_list->target_reset_issued = 1;
676 hd->resetPending = 1;
677 }
678}
679
680/**
681 * mptsas_dev_reset_complete
682 *
683 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
684 * enable work queue to finish off removing device from upper layers.
685 * then send next TARGET_RESET in the queue.
686 *
687 * @ioc
688 *
689 **/
690static void
691mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
692{
693 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
694 struct list_head *head = &hd->target_reset_list;
695 struct mptsas_target_reset_event *target_reset_list;
696 struct mptsas_hotplug_event *ev;
697 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
698 u8 id, channel;
699 __le64 sas_address;
700
701 if (list_empty(head))
702 return;
703
704 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
705
706 sas_event_data = &target_reset_list->sas_event_data;
707 id = sas_event_data->TargetID;
708 channel = sas_event_data->Bus;
709 hd->resetPending = 0;
710
711 /*
712 * retry target reset
713 */
714 if (!target_reset_list->target_reset_issued) {
715 if (mptsas_target_reset(ioc, channel, id)) {
716 target_reset_list->target_reset_issued = 1;
717 hd->resetPending = 1;
718 }
719 return;
720 }
721
722 /*
723 * enable work queue to remove device from upper layers
724 */
725 list_del(&target_reset_list->list);
726
727 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
728 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530729 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700730 ioc->name,__FUNCTION__, __LINE__));
731 return;
732 }
733
734 INIT_WORK(&ev->work, mptsas_hotplug_work);
735 ev->ioc = ioc;
736 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
737 ev->parent_handle =
738 le16_to_cpu(sas_event_data->ParentDevHandle);
739 ev->channel = channel;
740 ev->id =id;
741 ev->phy_id = sas_event_data->PhyNum;
742 memcpy(&sas_address, &sas_event_data->SASAddress,
743 sizeof(__le64));
744 ev->sas_address = le64_to_cpu(sas_address);
745 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
746 ev->event_type = MPTSAS_DEL_DEVICE;
747 schedule_work(&ev->work);
748 kfree(target_reset_list);
749
750 /*
751 * issue target reset to next device in the queue
752 */
753
754 head = &hd->target_reset_list;
755 if (list_empty(head))
756 return;
757
758 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
759 list);
760
761 sas_event_data = &target_reset_list->sas_event_data;
762 id = sas_event_data->TargetID;
763 channel = sas_event_data->Bus;
764
765 if (mptsas_target_reset(ioc, channel, id)) {
766 target_reset_list->target_reset_issued = 1;
767 hd->resetPending = 1;
768 }
769}
770
771/**
772 * mptsas_taskmgmt_complete
773 *
774 * @ioc
775 * @mf
776 * @mr
777 *
778 **/
779static int
780mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
781{
782 mptsas_dev_reset_complete(ioc);
783 return mptscsih_taskmgmt_complete(ioc, mf, mr);
784}
785
786/**
787 * mptscsih_ioc_reset
788 *
789 * @ioc
790 * @reset_phase
791 *
792 **/
793static int
794mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
795{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800796 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700797 struct mptsas_target_reset_event *target_reset_list, *n;
798 int rc;
799
800 rc = mptscsih_ioc_reset(ioc, reset_phase);
801
802 if (ioc->bus_type != SAS)
803 goto out;
804
805 if (reset_phase != MPT_IOC_POST_RESET)
806 goto out;
807
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800808 if (!ioc->sh || !ioc->sh->hostdata)
809 goto out;
810 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
811 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700812 goto out;
813
814 if (list_empty(&hd->target_reset_list))
815 goto out;
816
817 /* flush the target_reset_list */
818 list_for_each_entry_safe(target_reset_list, n,
819 &hd->target_reset_list, list) {
820 list_del(&target_reset_list->list);
821 kfree(target_reset_list);
822 }
823
824 out:
825 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600826}
827
Christoph Hellwige3094442006-02-16 13:25:36 +0100828static int
Moore, Eric52435432006-03-14 09:14:15 -0700829mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100830 u32 form, u32 form_specific)
831{
832 ConfigExtendedPageHeader_t hdr;
833 CONFIGPARMS cfg;
834 SasEnclosurePage0_t *buffer;
835 dma_addr_t dma_handle;
836 int error;
837 __le64 le_identifier;
838
839 memset(&hdr, 0, sizeof(hdr));
840 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
841 hdr.PageNumber = 0;
842 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
843 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
844
845 cfg.cfghdr.ehdr = &hdr;
846 cfg.physAddr = -1;
847 cfg.pageAddr = form + form_specific;
848 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
849 cfg.dir = 0; /* read */
850 cfg.timeout = 10;
851
852 error = mpt_config(ioc, &cfg);
853 if (error)
854 goto out;
855 if (!hdr.ExtPageLength) {
856 error = -ENXIO;
857 goto out;
858 }
859
860 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
861 &dma_handle);
862 if (!buffer) {
863 error = -ENOMEM;
864 goto out;
865 }
866
867 cfg.physAddr = dma_handle;
868 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
869
870 error = mpt_config(ioc, &cfg);
871 if (error)
872 goto out_free_consistent;
873
874 /* save config data */
875 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
876 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
877 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
878 enclosure->flags = le16_to_cpu(buffer->Flags);
879 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
880 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
881 enclosure->start_id = buffer->StartTargetID;
882 enclosure->start_channel = buffer->StartBus;
883 enclosure->sep_id = buffer->SEPTargetID;
884 enclosure->sep_channel = buffer->SEPBus;
885
886 out_free_consistent:
887 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
888 buffer, dma_handle);
889 out:
890 return error;
891}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200892
James Bottomleyf013db32006-03-18 14:54:36 -0600893static int
894mptsas_slave_configure(struct scsi_device *sdev)
895{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600896
James Bottomleye8bf3942006-07-11 17:49:34 -0400897 if (sdev->channel == MPTSAS_RAID_CHANNEL)
898 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600899
James Bottomleye8bf3942006-07-11 17:49:34 -0400900 sas_read_port_mode_page(sdev);
901
902 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600903 return mptscsih_slave_configure(sdev);
904}
905
Eric Moore547f9a22006-06-27 14:42:12 -0600906static int
907mptsas_target_alloc(struct scsi_target *starget)
908{
909 struct Scsi_Host *host = dev_to_shost(&starget->dev);
910 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
911 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700912 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600913 struct sas_rphy *rphy;
914 struct mptsas_portinfo *p;
915 int i;
916
917 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
918 if (!vtarget)
919 return -ENOMEM;
920
921 vtarget->starget = starget;
922 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700923 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
924 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600925 channel = 0;
926
Eric Moore793955f2007-01-29 09:42:20 -0700927 /*
928 * RAID volumes placed beyond the last expected port.
929 */
930 if (starget->channel == MPTSAS_RAID_CHANNEL) {
931 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
932 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
933 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600934 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700935 }
Eric Moore547f9a22006-06-27 14:42:12 -0600936
937 rphy = dev_to_rphy(starget->dev.parent);
938 mutex_lock(&hd->ioc->sas_topology_mutex);
939 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
940 for (i = 0; i < p->num_phys; i++) {
941 if (p->phy_info[i].attached.sas_address !=
942 rphy->identify.sas_address)
943 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700944 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600945 channel = p->phy_info[i].attached.channel;
946 mptsas_set_starget(&p->phy_info[i], starget);
947
948 /*
949 * Exposing hidden raid components
950 */
Eric Moore793955f2007-01-29 09:42:20 -0700951 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
952 id = mptscsih_raid_id_to_num(hd->ioc,
953 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600954 vtarget->tflags |=
955 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700956 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600957 }
958 mutex_unlock(&hd->ioc->sas_topology_mutex);
959 goto out;
960 }
961 }
962 mutex_unlock(&hd->ioc->sas_topology_mutex);
963
964 kfree(vtarget);
965 return -ENXIO;
966
967 out:
Eric Moore793955f2007-01-29 09:42:20 -0700968 vtarget->id = id;
969 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600970 starget->hostdata = vtarget;
971 return 0;
972}
973
974static void
975mptsas_target_destroy(struct scsi_target *starget)
976{
977 struct Scsi_Host *host = dev_to_shost(&starget->dev);
978 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
979 struct sas_rphy *rphy;
980 struct mptsas_portinfo *p;
981 int i;
982
983 if (!starget->hostdata)
984 return;
985
James Bottomleye8bf3942006-07-11 17:49:34 -0400986 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600987 goto out;
988
989 rphy = dev_to_rphy(starget->dev.parent);
990 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
991 for (i = 0; i < p->num_phys; i++) {
992 if (p->phy_info[i].attached.sas_address !=
993 rphy->identify.sas_address)
994 continue;
995 mptsas_set_starget(&p->phy_info[i], NULL);
996 goto out;
997 }
998 }
999
1000 out:
1001 kfree(starget->hostdata);
1002 starget->hostdata = NULL;
1003}
1004
1005
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001006static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001007mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001008{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001009 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001010 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1011 struct sas_rphy *rphy;
1012 struct mptsas_portinfo *p;
1013 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001014 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001015 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001016
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001017 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001018 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -06001019 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001020 hd->ioc->name, sizeof(VirtDevice));
1021 return -ENOMEM;
1022 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001023 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -06001024 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001025
James Bottomleye8bf3942006-07-11 17:49:34 -04001026 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001027 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001028
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001029 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001030 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001031 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1032 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001033 if (p->phy_info[i].attached.sas_address !=
1034 rphy->identify.sas_address)
1035 continue;
1036 vdev->lun = sdev->lun;
1037 /*
1038 * Exposing hidden raid components
1039 */
1040 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001041 p->phy_info[i].attached.channel,
1042 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001043 sdev->no_uld_attach = 1;
1044 mutex_unlock(&hd->ioc->sas_topology_mutex);
1045 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001046 }
1047 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001048 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001049
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001050 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001051 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001052
1053 out:
Eric Moore547f9a22006-06-27 14:42:12 -06001054 vdev->vtarget->num_luns++;
1055 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001056 return 0;
1057}
1058
Eric Moore547f9a22006-06-27 14:42:12 -06001059static int
1060mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001061{
Eric Moore547f9a22006-06-27 14:42:12 -06001062 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001063
Eric Moore793955f2007-01-29 09:42:20 -07001064 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001065 SCpnt->result = DID_NO_CONNECT << 16;
1066 done(SCpnt);
1067 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001068 }
Eric Moore547f9a22006-06-27 14:42:12 -06001069
Eric Moore793955f2007-01-29 09:42:20 -07001070// scsi_print_command(SCpnt);
1071
Eric Moore547f9a22006-06-27 14:42:12 -06001072 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001073}
1074
Eric Moore547f9a22006-06-27 14:42:12 -06001075
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001076static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001077 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001078 .proc_name = "mptsas",
1079 .proc_info = mptscsih_proc_info,
1080 .name = "MPT SPI Host",
1081 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001082 .queuecommand = mptsas_qcmd,
1083 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001084 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001085 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001086 .target_destroy = mptsas_target_destroy,
1087 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001088 .change_queue_depth = mptscsih_change_queue_depth,
1089 .eh_abort_handler = mptscsih_abort,
1090 .eh_device_reset_handler = mptscsih_dev_reset,
1091 .eh_bus_reset_handler = mptscsih_bus_reset,
1092 .eh_host_reset_handler = mptscsih_host_reset,
1093 .bios_param = mptscsih_bios_param,
1094 .can_queue = MPT_FC_CAN_QUEUE,
1095 .this_id = -1,
1096 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1097 .max_sectors = 8192,
1098 .cmd_per_lun = 7,
1099 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301100 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001101};
1102
Christoph Hellwigb5141122005-10-28 22:07:41 +02001103static int mptsas_get_linkerrors(struct sas_phy *phy)
1104{
1105 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1106 ConfigExtendedPageHeader_t hdr;
1107 CONFIGPARMS cfg;
1108 SasPhyPage1_t *buffer;
1109 dma_addr_t dma_handle;
1110 int error;
1111
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001112 /* FIXME: only have link errors on local phys */
1113 if (!scsi_is_sas_phy_local(phy))
1114 return -EINVAL;
1115
Christoph Hellwigb5141122005-10-28 22:07:41 +02001116 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1117 hdr.ExtPageLength = 0;
1118 hdr.PageNumber = 1 /* page number 1*/;
1119 hdr.Reserved1 = 0;
1120 hdr.Reserved2 = 0;
1121 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1122 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1123
1124 cfg.cfghdr.ehdr = &hdr;
1125 cfg.physAddr = -1;
1126 cfg.pageAddr = phy->identify.phy_identifier;
1127 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1128 cfg.dir = 0; /* read */
1129 cfg.timeout = 10;
1130
1131 error = mpt_config(ioc, &cfg);
1132 if (error)
1133 return error;
1134 if (!hdr.ExtPageLength)
1135 return -ENXIO;
1136
1137 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1138 &dma_handle);
1139 if (!buffer)
1140 return -ENOMEM;
1141
1142 cfg.physAddr = dma_handle;
1143 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1144
1145 error = mpt_config(ioc, &cfg);
1146 if (error)
1147 goto out_free_consistent;
1148
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301149 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001150
1151 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1152 phy->running_disparity_error_count =
1153 le32_to_cpu(buffer->RunningDisparityErrorCount);
1154 phy->loss_of_dword_sync_count =
1155 le32_to_cpu(buffer->LossDwordSynchCount);
1156 phy->phy_reset_problem_count =
1157 le32_to_cpu(buffer->PhyResetProblemCount);
1158
1159 out_free_consistent:
1160 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1161 buffer, dma_handle);
1162 return error;
1163}
1164
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001165static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1166 MPT_FRAME_HDR *reply)
1167{
1168 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1169 if (reply != NULL) {
1170 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1171 memcpy(ioc->sas_mgmt.reply, reply,
1172 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1173 }
1174 complete(&ioc->sas_mgmt.done);
1175 return 1;
1176}
1177
1178static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1179{
1180 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1181 SasIoUnitControlRequest_t *req;
1182 SasIoUnitControlReply_t *reply;
1183 MPT_FRAME_HDR *mf;
1184 MPIHeader_t *hdr;
1185 unsigned long timeleft;
1186 int error = -ERESTARTSYS;
1187
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001188 /* FIXME: fusion doesn't allow non-local phy reset */
1189 if (!scsi_is_sas_phy_local(phy))
1190 return -EINVAL;
1191
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001192 /* not implemented for expanders */
1193 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1194 return -ENXIO;
1195
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001196 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001197 goto out;
1198
1199 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1200 if (!mf) {
1201 error = -ENOMEM;
1202 goto out_unlock;
1203 }
1204
1205 hdr = (MPIHeader_t *) mf;
1206 req = (SasIoUnitControlRequest_t *)mf;
1207 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1208 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1209 req->MsgContext = hdr->MsgContext;
1210 req->Operation = hard_reset ?
1211 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1212 req->PhyNum = phy->identify.phy_identifier;
1213
1214 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1215
1216 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1217 10 * HZ);
1218 if (!timeleft) {
1219 /* On timeout reset the board */
1220 mpt_free_msg_frame(ioc, mf);
1221 mpt_HardResetHandler(ioc, CAN_SLEEP);
1222 error = -ETIMEDOUT;
1223 goto out_unlock;
1224 }
1225
1226 /* a reply frame is expected */
1227 if ((ioc->sas_mgmt.status &
1228 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1229 error = -ENXIO;
1230 goto out_unlock;
1231 }
1232
1233 /* process the completed Reply Message Frame */
1234 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1235 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1236 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1237 __FUNCTION__,
1238 reply->IOCStatus,
1239 reply->IOCLogInfo);
1240 error = -ENXIO;
1241 goto out_unlock;
1242 }
1243
1244 error = 0;
1245
1246 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001247 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001248 out:
1249 return error;
1250}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001251
Christoph Hellwige3094442006-02-16 13:25:36 +01001252static int
1253mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1254{
1255 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1256 int i, error;
1257 struct mptsas_portinfo *p;
1258 struct mptsas_enclosure enclosure_info;
1259 u64 enclosure_handle;
1260
1261 mutex_lock(&ioc->sas_topology_mutex);
1262 list_for_each_entry(p, &ioc->sas_topology, list) {
1263 for (i = 0; i < p->num_phys; i++) {
1264 if (p->phy_info[i].attached.sas_address ==
1265 rphy->identify.sas_address) {
1266 enclosure_handle = p->phy_info[i].
1267 attached.handle_enclosure;
1268 goto found_info;
1269 }
1270 }
1271 }
1272 mutex_unlock(&ioc->sas_topology_mutex);
1273 return -ENXIO;
1274
1275 found_info:
1276 mutex_unlock(&ioc->sas_topology_mutex);
1277 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001278 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001279 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1280 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1281 if (!error)
1282 *identifier = enclosure_info.enclosure_logical_id;
1283 return error;
1284}
1285
1286static int
1287mptsas_get_bay_identifier(struct sas_rphy *rphy)
1288{
1289 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1290 struct mptsas_portinfo *p;
1291 int i, rc;
1292
1293 mutex_lock(&ioc->sas_topology_mutex);
1294 list_for_each_entry(p, &ioc->sas_topology, list) {
1295 for (i = 0; i < p->num_phys; i++) {
1296 if (p->phy_info[i].attached.sas_address ==
1297 rphy->identify.sas_address) {
1298 rc = p->phy_info[i].attached.slot;
1299 goto out;
1300 }
1301 }
1302 }
1303 rc = -ENXIO;
1304 out:
1305 mutex_unlock(&ioc->sas_topology_mutex);
1306 return rc;
1307}
1308
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001309static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1310 struct request *req)
1311{
1312 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1313 MPT_FRAME_HDR *mf;
1314 SmpPassthroughRequest_t *smpreq;
1315 struct request *rsp = req->next_rq;
1316 int ret;
1317 int flagsLength;
1318 unsigned long timeleft;
1319 char *psge;
1320 dma_addr_t dma_addr_in = 0;
1321 dma_addr_t dma_addr_out = 0;
1322 u64 sas_address = 0;
1323
1324 if (!rsp) {
1325 printk(KERN_ERR "%s: the smp response space is missing\n",
1326 __FUNCTION__);
1327 return -EINVAL;
1328 }
1329
1330 /* do we need to support multiple segments? */
1331 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1332 printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
1333 __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1334 rsp->bio->bi_vcnt, rsp->data_len);
1335 return -EINVAL;
1336 }
1337
1338 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1339 if (ret)
1340 goto out;
1341
1342 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1343 if (!mf) {
1344 ret = -ENOMEM;
1345 goto out_unlock;
1346 }
1347
1348 smpreq = (SmpPassthroughRequest_t *)mf;
1349 memset(smpreq, 0, sizeof(*smpreq));
1350
1351 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1352 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1353
1354 if (rphy)
1355 sas_address = rphy->identify.sas_address;
1356 else {
1357 struct mptsas_portinfo *port_info;
1358
1359 mutex_lock(&ioc->sas_topology_mutex);
1360 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1361 if (port_info && port_info->phy_info)
1362 sas_address =
1363 port_info->phy_info[0].phy->identify.sas_address;
1364 mutex_unlock(&ioc->sas_topology_mutex);
1365 }
1366
1367 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1368
1369 psge = (char *)
1370 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1371
1372 /* request */
1373 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1374 MPI_SGE_FLAGS_END_OF_BUFFER |
1375 MPI_SGE_FLAGS_DIRECTION |
1376 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1377 flagsLength |= (req->data_len - 4);
1378
1379 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1380 req->data_len, PCI_DMA_BIDIRECTIONAL);
1381 if (!dma_addr_out)
1382 goto put_mf;
1383 mpt_add_sge(psge, flagsLength, dma_addr_out);
1384 psge += (sizeof(u32) + sizeof(dma_addr_t));
1385
1386 /* response */
1387 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1388 flagsLength |= rsp->data_len + 4;
1389 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1390 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1391 if (!dma_addr_in)
1392 goto unmap;
1393 mpt_add_sge(psge, flagsLength, dma_addr_in);
1394
1395 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1396
1397 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1398 if (!timeleft) {
1399 printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
1400 /* On timeout reset the board */
1401 mpt_HardResetHandler(ioc, CAN_SLEEP);
1402 ret = -ETIMEDOUT;
1403 goto unmap;
1404 }
1405 mf = NULL;
1406
1407 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1408 SmpPassthroughReply_t *smprep;
1409
1410 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1411 memcpy(req->sense, smprep, sizeof(*smprep));
1412 req->sense_len = sizeof(*smprep);
1413 } else {
1414 printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
1415 __FUNCTION__);
1416 ret = -ENXIO;
1417 }
1418unmap:
1419 if (dma_addr_out)
1420 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1421 PCI_DMA_BIDIRECTIONAL);
1422 if (dma_addr_in)
1423 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1424 PCI_DMA_BIDIRECTIONAL);
1425put_mf:
1426 if (mf)
1427 mpt_free_msg_frame(ioc, mf);
1428out_unlock:
1429 mutex_unlock(&ioc->sas_mgmt.mutex);
1430out:
1431 return ret;
1432}
1433
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001434static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001435 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001436 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1437 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001438 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001439 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001440};
1441
1442static struct scsi_transport_template *mptsas_transport_template;
1443
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001444static int
1445mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1446{
1447 ConfigExtendedPageHeader_t hdr;
1448 CONFIGPARMS cfg;
1449 SasIOUnitPage0_t *buffer;
1450 dma_addr_t dma_handle;
1451 int error, i;
1452
1453 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1454 hdr.ExtPageLength = 0;
1455 hdr.PageNumber = 0;
1456 hdr.Reserved1 = 0;
1457 hdr.Reserved2 = 0;
1458 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1459 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1460
1461 cfg.cfghdr.ehdr = &hdr;
1462 cfg.physAddr = -1;
1463 cfg.pageAddr = 0;
1464 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1465 cfg.dir = 0; /* read */
1466 cfg.timeout = 10;
1467
1468 error = mpt_config(ioc, &cfg);
1469 if (error)
1470 goto out;
1471 if (!hdr.ExtPageLength) {
1472 error = -ENXIO;
1473 goto out;
1474 }
1475
1476 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1477 &dma_handle);
1478 if (!buffer) {
1479 error = -ENOMEM;
1480 goto out;
1481 }
1482
1483 cfg.physAddr = dma_handle;
1484 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1485
1486 error = mpt_config(ioc, &cfg);
1487 if (error)
1488 goto out_free_consistent;
1489
1490 port_info->num_phys = buffer->NumPhys;
1491 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001492 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001493 if (!port_info->phy_info) {
1494 error = -ENOMEM;
1495 goto out_free_consistent;
1496 }
1497
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301498 ioc->nvdata_version_persistent =
1499 le16_to_cpu(buffer->NvdataVersionPersistent);
1500 ioc->nvdata_version_default =
1501 le16_to_cpu(buffer->NvdataVersionDefault);
1502
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001503 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301504 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001505 port_info->phy_info[i].phy_id = i;
1506 port_info->phy_info[i].port_id =
1507 buffer->PhyData[i].Port;
1508 port_info->phy_info[i].negotiated_link_rate =
1509 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001510 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001511 port_info->phy_info[i].handle =
1512 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001513 }
1514
1515 out_free_consistent:
1516 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1517 buffer, dma_handle);
1518 out:
1519 return error;
1520}
1521
1522static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301523mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1524{
1525 ConfigExtendedPageHeader_t hdr;
1526 CONFIGPARMS cfg;
1527 SasIOUnitPage1_t *buffer;
1528 dma_addr_t dma_handle;
1529 int error;
1530 u16 device_missing_delay;
1531
1532 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1533 memset(&cfg, 0, sizeof(CONFIGPARMS));
1534
1535 cfg.cfghdr.ehdr = &hdr;
1536 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1537 cfg.timeout = 10;
1538 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1539 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1540 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1541 cfg.cfghdr.ehdr->PageNumber = 1;
1542
1543 error = mpt_config(ioc, &cfg);
1544 if (error)
1545 goto out;
1546 if (!hdr.ExtPageLength) {
1547 error = -ENXIO;
1548 goto out;
1549 }
1550
1551 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1552 &dma_handle);
1553 if (!buffer) {
1554 error = -ENOMEM;
1555 goto out;
1556 }
1557
1558 cfg.physAddr = dma_handle;
1559 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1560
1561 error = mpt_config(ioc, &cfg);
1562 if (error)
1563 goto out_free_consistent;
1564
1565 ioc->io_missing_delay =
1566 le16_to_cpu(buffer->IODeviceMissingDelay);
1567 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1568 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1569 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1570 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1571
1572 out_free_consistent:
1573 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1574 buffer, dma_handle);
1575 out:
1576 return error;
1577}
1578
1579static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001580mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1581 u32 form, u32 form_specific)
1582{
1583 ConfigExtendedPageHeader_t hdr;
1584 CONFIGPARMS cfg;
1585 SasPhyPage0_t *buffer;
1586 dma_addr_t dma_handle;
1587 int error;
1588
1589 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1590 hdr.ExtPageLength = 0;
1591 hdr.PageNumber = 0;
1592 hdr.Reserved1 = 0;
1593 hdr.Reserved2 = 0;
1594 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1595 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1596
1597 cfg.cfghdr.ehdr = &hdr;
1598 cfg.dir = 0; /* read */
1599 cfg.timeout = 10;
1600
1601 /* Get Phy Pg 0 for each Phy. */
1602 cfg.physAddr = -1;
1603 cfg.pageAddr = form + form_specific;
1604 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1605
1606 error = mpt_config(ioc, &cfg);
1607 if (error)
1608 goto out;
1609
1610 if (!hdr.ExtPageLength) {
1611 error = -ENXIO;
1612 goto out;
1613 }
1614
1615 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1616 &dma_handle);
1617 if (!buffer) {
1618 error = -ENOMEM;
1619 goto out;
1620 }
1621
1622 cfg.physAddr = dma_handle;
1623 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1624
1625 error = mpt_config(ioc, &cfg);
1626 if (error)
1627 goto out_free_consistent;
1628
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301629 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001630
1631 phy_info->hw_link_rate = buffer->HwLinkRate;
1632 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1633 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1634 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1635
1636 out_free_consistent:
1637 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1638 buffer, dma_handle);
1639 out:
1640 return error;
1641}
1642
1643static int
1644mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1645 u32 form, u32 form_specific)
1646{
1647 ConfigExtendedPageHeader_t hdr;
1648 CONFIGPARMS cfg;
1649 SasDevicePage0_t *buffer;
1650 dma_addr_t dma_handle;
1651 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001652 int error=0;
1653
1654 if (ioc->sas_discovery_runtime &&
1655 mptsas_is_end_device(device_info))
1656 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001657
1658 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1659 hdr.ExtPageLength = 0;
1660 hdr.PageNumber = 0;
1661 hdr.Reserved1 = 0;
1662 hdr.Reserved2 = 0;
1663 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1664 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1665
1666 cfg.cfghdr.ehdr = &hdr;
1667 cfg.pageAddr = form + form_specific;
1668 cfg.physAddr = -1;
1669 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1670 cfg.dir = 0; /* read */
1671 cfg.timeout = 10;
1672
Moore, Ericdb9c9172006-03-14 09:14:18 -07001673 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001674 error = mpt_config(ioc, &cfg);
1675 if (error)
1676 goto out;
1677 if (!hdr.ExtPageLength) {
1678 error = -ENXIO;
1679 goto out;
1680 }
1681
1682 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1683 &dma_handle);
1684 if (!buffer) {
1685 error = -ENOMEM;
1686 goto out;
1687 }
1688
1689 cfg.physAddr = dma_handle;
1690 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1691
1692 error = mpt_config(ioc, &cfg);
1693 if (error)
1694 goto out_free_consistent;
1695
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301696 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001697
1698 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001699 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001700 device_info->handle_enclosure =
1701 le16_to_cpu(buffer->EnclosureHandle);
1702 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001703 device_info->phy_id = buffer->PhyNum;
1704 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001705 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001706 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001707 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001708 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1709 device_info->sas_address = le64_to_cpu(sas_address);
1710 device_info->device_info =
1711 le32_to_cpu(buffer->DeviceInfo);
1712
1713 out_free_consistent:
1714 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1715 buffer, dma_handle);
1716 out:
1717 return error;
1718}
1719
1720static int
1721mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1722 u32 form, u32 form_specific)
1723{
1724 ConfigExtendedPageHeader_t hdr;
1725 CONFIGPARMS cfg;
1726 SasExpanderPage0_t *buffer;
1727 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001728 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001729
1730 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1731 hdr.ExtPageLength = 0;
1732 hdr.PageNumber = 0;
1733 hdr.Reserved1 = 0;
1734 hdr.Reserved2 = 0;
1735 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1736 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1737
1738 cfg.cfghdr.ehdr = &hdr;
1739 cfg.physAddr = -1;
1740 cfg.pageAddr = form + form_specific;
1741 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1742 cfg.dir = 0; /* read */
1743 cfg.timeout = 10;
1744
Moore, Ericdb9c9172006-03-14 09:14:18 -07001745 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001746 error = mpt_config(ioc, &cfg);
1747 if (error)
1748 goto out;
1749
1750 if (!hdr.ExtPageLength) {
1751 error = -ENXIO;
1752 goto out;
1753 }
1754
1755 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1756 &dma_handle);
1757 if (!buffer) {
1758 error = -ENOMEM;
1759 goto out;
1760 }
1761
1762 cfg.physAddr = dma_handle;
1763 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1764
1765 error = mpt_config(ioc, &cfg);
1766 if (error)
1767 goto out_free_consistent;
1768
1769 /* save config data */
1770 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001771 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001772 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001773 if (!port_info->phy_info) {
1774 error = -ENOMEM;
1775 goto out_free_consistent;
1776 }
1777
Eric Moore2ecce492007-01-29 09:47:08 -07001778 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001779 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001780 port_info->phy_info[i].handle =
1781 le16_to_cpu(buffer->DevHandle);
1782 }
Eric Moore547f9a22006-06-27 14:42:12 -06001783
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001784 out_free_consistent:
1785 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1786 buffer, dma_handle);
1787 out:
1788 return error;
1789}
1790
1791static int
1792mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1793 u32 form, u32 form_specific)
1794{
1795 ConfigExtendedPageHeader_t hdr;
1796 CONFIGPARMS cfg;
1797 SasExpanderPage1_t *buffer;
1798 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001799 int error=0;
1800
1801 if (ioc->sas_discovery_runtime &&
1802 mptsas_is_end_device(&phy_info->attached))
1803 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001804
1805 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1806 hdr.ExtPageLength = 0;
1807 hdr.PageNumber = 1;
1808 hdr.Reserved1 = 0;
1809 hdr.Reserved2 = 0;
1810 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1811 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1812
1813 cfg.cfghdr.ehdr = &hdr;
1814 cfg.physAddr = -1;
1815 cfg.pageAddr = form + form_specific;
1816 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1817 cfg.dir = 0; /* read */
1818 cfg.timeout = 10;
1819
1820 error = mpt_config(ioc, &cfg);
1821 if (error)
1822 goto out;
1823
1824 if (!hdr.ExtPageLength) {
1825 error = -ENXIO;
1826 goto out;
1827 }
1828
1829 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1830 &dma_handle);
1831 if (!buffer) {
1832 error = -ENOMEM;
1833 goto out;
1834 }
1835
1836 cfg.physAddr = dma_handle;
1837 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1838
1839 error = mpt_config(ioc, &cfg);
1840 if (error)
1841 goto out_free_consistent;
1842
1843
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301844 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001845
1846 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001847 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848 phy_info->port_id = buffer->PhysicalPort;
1849 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1850 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1851 phy_info->hw_link_rate = buffer->HwLinkRate;
1852 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1853 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1854
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001855 out_free_consistent:
1856 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1857 buffer, dma_handle);
1858 out:
1859 return error;
1860}
1861
1862static void
1863mptsas_parse_device_info(struct sas_identify *identify,
1864 struct mptsas_devinfo *device_info)
1865{
1866 u16 protocols;
1867
1868 identify->sas_address = device_info->sas_address;
1869 identify->phy_identifier = device_info->phy_id;
1870
1871 /*
1872 * Fill in Phy Initiator Port Protocol.
1873 * Bits 6:3, more than one bit can be set, fall through cases.
1874 */
1875 protocols = device_info->device_info & 0x78;
1876 identify->initiator_port_protocols = 0;
1877 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1878 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1879 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1880 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1881 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1882 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1883 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1884 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1885
1886 /*
1887 * Fill in Phy Target Port Protocol.
1888 * Bits 10:7, more than one bit can be set, fall through cases.
1889 */
1890 protocols = device_info->device_info & 0x780;
1891 identify->target_port_protocols = 0;
1892 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1893 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1894 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1895 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1896 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1897 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1898 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1899 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1900
1901 /*
1902 * Fill in Attached device type.
1903 */
1904 switch (device_info->device_info &
1905 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1906 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1907 identify->device_type = SAS_PHY_UNUSED;
1908 break;
1909 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1910 identify->device_type = SAS_END_DEVICE;
1911 break;
1912 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1913 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1914 break;
1915 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1916 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1917 break;
1918 }
1919}
1920
1921static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001922 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001923{
Moore, Erice6b2d762006-03-14 09:14:24 -07001924 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001925 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001926 struct sas_port *port;
1927 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001928
Eric Moore547f9a22006-06-27 14:42:12 -06001929 if (!dev) {
1930 error = -ENODEV;
1931 goto out;
1932 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001933
1934 if (!phy_info->phy) {
1935 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001936 if (!phy) {
1937 error = -ENOMEM;
1938 goto out;
1939 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001940 } else
1941 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001942
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001943 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001944
1945 /*
1946 * Set Negotiated link rate.
1947 */
1948 switch (phy_info->negotiated_link_rate) {
1949 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001950 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001951 break;
1952 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001953 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001954 break;
1955 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001956 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001957 break;
1958 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001959 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001960 break;
1961 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1962 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1963 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001964 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001965 break;
1966 }
1967
1968 /*
1969 * Set Max hardware link rate.
1970 */
1971 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1972 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001973 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001974 break;
1975 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001976 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001977 break;
1978 default:
1979 break;
1980 }
1981
1982 /*
1983 * Set Max programmed link rate.
1984 */
1985 switch (phy_info->programmed_link_rate &
1986 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1987 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001988 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001989 break;
1990 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001991 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001992 break;
1993 default:
1994 break;
1995 }
1996
1997 /*
1998 * Set Min hardware link rate.
1999 */
2000 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2001 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002002 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002003 break;
2004 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002005 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002006 break;
2007 default:
2008 break;
2009 }
2010
2011 /*
2012 * Set Min programmed link rate.
2013 */
2014 switch (phy_info->programmed_link_rate &
2015 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2016 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002017 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002018 break;
2019 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002020 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002021 break;
2022 default:
2023 break;
2024 }
2025
Moore, Erice6b2d762006-03-14 09:14:24 -07002026 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002027
Moore, Erice6b2d762006-03-14 09:14:24 -07002028 error = sas_phy_add(phy);
2029 if (error) {
2030 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002031 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002032 }
2033 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002034 }
2035
Eric Moore547f9a22006-06-27 14:42:12 -06002036 if (!phy_info->attached.handle ||
2037 !phy_info->port_details)
2038 goto out;
2039
2040 port = mptsas_get_port(phy_info);
2041 ioc = phy_to_ioc(phy_info->phy);
2042
2043 if (phy_info->sas_port_add_phy) {
2044
2045 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002046 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002047 if (!port) {
2048 error = -ENOMEM;
2049 goto out;
2050 }
2051 error = sas_port_add(port);
2052 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302053 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002054 "%s: exit at line=%d\n", ioc->name,
2055 __FUNCTION__, __LINE__));
2056 goto out;
2057 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302058 mptsas_set_port(ioc, phy_info, port);
2059 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -06002060 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
2061 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002062 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302063 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
Eric Moore547f9a22006-06-27 14:42:12 -06002064 phy_info->phy_id));
2065 sas_port_add_phy(port, phy_info->phy);
2066 phy_info->sas_port_add_phy = 0;
2067 }
2068
2069 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002070
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002071 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002072 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002073 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002074
James Bottomley2686de22006-06-30 12:54:02 -05002075 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002076 /*
2077 * Let the hotplug_work thread handle processing
2078 * the adding/removing of devices that occur
2079 * after start of day.
2080 */
2081 if (ioc->sas_discovery_runtime &&
2082 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002083 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002084
James Bottomleyf013db32006-03-18 14:54:36 -06002085 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002086 if (scsi_is_host_device(parent)) {
2087 struct mptsas_portinfo *port_info;
2088 int i;
2089
2090 mutex_lock(&ioc->sas_topology_mutex);
2091 port_info = mptsas_find_portinfo_by_handle(ioc,
2092 ioc->handle);
2093 mutex_unlock(&ioc->sas_topology_mutex);
2094
2095 for (i = 0; i < port_info->num_phys; i++)
2096 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002097 identify.sas_address) {
2098 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002099 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002100 }
James Bottomley2686de22006-06-30 12:54:02 -05002101
2102 } else if (scsi_is_sas_rphy(parent)) {
2103 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2104 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002105 parent_rphy->identify.sas_address) {
2106 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002107 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002108 }
James Bottomley2686de22006-06-30 12:54:02 -05002109 }
2110
James Bottomleyf013db32006-03-18 14:54:36 -06002111 switch (identify.device_type) {
2112 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002113 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002114 break;
2115 case SAS_EDGE_EXPANDER_DEVICE:
2116 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002117 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002118 break;
2119 default:
2120 rphy = NULL;
2121 break;
2122 }
Eric Moore547f9a22006-06-27 14:42:12 -06002123 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302124 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002125 "%s: exit at line=%d\n", ioc->name,
2126 __FUNCTION__, __LINE__));
2127 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002128 }
2129
Eric Moore547f9a22006-06-27 14:42:12 -06002130 rphy->identify = identify;
2131 error = sas_rphy_add(rphy);
2132 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302133 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002134 "%s: exit at line=%d\n", ioc->name,
2135 __FUNCTION__, __LINE__));
2136 sas_rphy_free(rphy);
2137 goto out;
2138 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302139 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002140 }
2141
Eric Moore547f9a22006-06-27 14:42:12 -06002142 out:
2143 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002144}
2145
2146static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002147mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002148{
Moore, Erice6b2d762006-03-14 09:14:24 -07002149 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002150 int error = -ENOMEM, i;
2151
Moore, Erice6b2d762006-03-14 09:14:24 -07002152 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2153 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002154 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002155
Moore, Erice6b2d762006-03-14 09:14:24 -07002156 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002157 if (error)
2158 goto out_free_port_info;
2159
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302160 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002161 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002162 ioc->handle = hba->phy_info[0].handle;
2163 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002164 if (!port_info) {
2165 port_info = hba;
2166 list_add_tail(&port_info->list, &ioc->sas_topology);
2167 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002168 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002169 port_info->phy_info[i].negotiated_link_rate =
2170 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002171 port_info->phy_info[i].handle =
2172 hba->phy_info[i].handle;
2173 port_info->phy_info[i].port_id =
2174 hba->phy_info[i].port_id;
2175 }
Eric Moore547f9a22006-06-27 14:42:12 -06002176 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002177 kfree(hba);
2178 hba = NULL;
2179 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002180 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002181 for (i = 0; i < port_info->num_phys; i++) {
2182 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2183 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2184 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2185
2186 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002187 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2188 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2189 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002190 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002191 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002192 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002193 mptsas_sas_device_pg0(ioc,
2194 &port_info->phy_info[i].attached,
2195 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2196 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2197 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002198 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002199
Eric Moore547f9a22006-06-27 14:42:12 -06002200 mptsas_setup_wide_ports(ioc, port_info);
2201
2202 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002203 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002204 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002205
2206 return 0;
2207
2208 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002209 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002210 out:
2211 return error;
2212}
2213
2214static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002215mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002216{
Moore, Erice6b2d762006-03-14 09:14:24 -07002217 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002218 struct device *parent;
2219 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002220 int error = -ENOMEM, i, j;
2221
Moore, Erice6b2d762006-03-14 09:14:24 -07002222 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2223 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002224 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002225
Moore, Erice6b2d762006-03-14 09:14:24 -07002226 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002227 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2228 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002229 if (error)
2230 goto out_free_port_info;
2231
Eric Moore2ecce492007-01-29 09:47:08 -07002232 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002233
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002234 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002235 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2236 if (!port_info) {
2237 port_info = ex;
2238 list_add_tail(&port_info->list, &ioc->sas_topology);
2239 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002240 for (i = 0; i < ex->num_phys; i++) {
2241 port_info->phy_info[i].handle =
2242 ex->phy_info[i].handle;
2243 port_info->phy_info[i].port_id =
2244 ex->phy_info[i].port_id;
2245 }
Eric Moore547f9a22006-06-27 14:42:12 -06002246 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002247 kfree(ex);
2248 ex = NULL;
2249 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002250 mutex_unlock(&ioc->sas_topology_mutex);
2251
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002252 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002253 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2254 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2255 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2256
2257 if (port_info->phy_info[i].identify.handle) {
2258 mptsas_sas_device_pg0(ioc,
2259 &port_info->phy_info[i].identify,
2260 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2261 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2262 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002263 port_info->phy_info[i].identify.phy_id =
2264 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002265 }
2266
2267 if (port_info->phy_info[i].attached.handle) {
2268 mptsas_sas_device_pg0(ioc,
2269 &port_info->phy_info[i].attached,
2270 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2271 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2272 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002273 port_info->phy_info[i].attached.phy_id =
2274 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002275 }
Eric Moore547f9a22006-06-27 14:42:12 -06002276 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002277
Eric Moore547f9a22006-06-27 14:42:12 -06002278 parent = &ioc->sh->shost_gendev;
2279 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002280 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002281 list_for_each_entry(p, &ioc->sas_topology, list) {
2282 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002283 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002284 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002285 continue;
2286 rphy = mptsas_get_rphy(&p->phy_info[j]);
2287 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002288 }
2289 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002290 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002291 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002292
Eric Moore547f9a22006-06-27 14:42:12 -06002293 mptsas_setup_wide_ports(ioc, port_info);
2294
2295 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002296 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002297 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002298
2299 return 0;
2300
2301 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002302 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002303 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002304 kfree(ex);
2305 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002306 out:
2307 return error;
2308}
2309
Moore, Erice6b2d762006-03-14 09:14:24 -07002310/*
2311 * mptsas_delete_expander_phys
2312 *
2313 *
2314 * This will traverse topology, and remove expanders
2315 * that are no longer present
2316 */
2317static void
2318mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2319{
2320 struct mptsas_portinfo buffer;
2321 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002322 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002323 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002324 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002325 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002326
2327 mutex_lock(&ioc->sas_topology_mutex);
2328 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2329
2330 if (port_info->phy_info &&
2331 (!(port_info->phy_info[0].identify.device_info &
2332 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2333 continue;
2334
2335 if (mptsas_sas_expander_pg0(ioc, &buffer,
2336 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002337 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2338 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002339
2340 /*
2341 * Obtain the port_info instance to the parent port
2342 */
2343 parent = mptsas_find_portinfo_by_handle(ioc,
2344 port_info->phy_info[0].identify.handle_parent);
2345
2346 if (!parent)
2347 goto next_port;
2348
Eric Moore547f9a22006-06-27 14:42:12 -06002349 expander_sas_address =
2350 port_info->phy_info[0].identify.sas_address;
2351
Moore, Erice6b2d762006-03-14 09:14:24 -07002352 /*
2353 * Delete rphys in the parent that point
2354 * to this expander. The transport layer will
2355 * cleanup all the children.
2356 */
Eric Moore547f9a22006-06-27 14:42:12 -06002357 phy_info = parent->phy_info;
2358 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2359 port = mptsas_get_port(phy_info);
2360 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002361 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002362 if (phy_info->attached.sas_address !=
2363 expander_sas_address)
2364 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302365 dsaswideprintk(ioc,
2366 dev_printk(KERN_DEBUG, &port->dev,
2367 "delete port (%d)\n", port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002368 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302369 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002370 }
2371 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002372
2373 phy_info = port_info->phy_info;
2374 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302375 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002376
Moore, Erice6b2d762006-03-14 09:14:24 -07002377 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002378 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002379 kfree(port_info);
2380 }
2381 /*
2382 * Free this memory allocated from inside
2383 * mptsas_sas_expander_pg0
2384 */
Eric Moore547f9a22006-06-27 14:42:12 -06002385 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002386 }
2387 mutex_unlock(&ioc->sas_topology_mutex);
2388}
2389
2390/*
2391 * Start of day discovery
2392 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002393static void
2394mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2395{
2396 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002397 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002398
Moore, Erice6b2d762006-03-14 09:14:24 -07002399 mutex_lock(&ioc->sas_discovery_mutex);
2400 mptsas_probe_hba_phys(ioc);
2401 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002402 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002403 /*
2404 Reporting RAID volumes.
2405 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002406 if (!ioc->ir_firmware)
2407 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002408 if (!ioc->raid_data.pIocPg2)
2409 goto out;
2410 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2411 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002412 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002413 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002414 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2415 }
2416 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002417 mutex_unlock(&ioc->sas_discovery_mutex);
2418}
2419
2420/*
2421 * Work queue thread to handle Runtime discovery
2422 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002423 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002424 */
2425static void
Eric Moore547f9a22006-06-27 14:42:12 -06002426__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002427{
Moore, Erice6b2d762006-03-14 09:14:24 -07002428 u32 handle = 0xFFFF;
2429
Moore, Erice6b2d762006-03-14 09:14:24 -07002430 ioc->sas_discovery_runtime=1;
2431 mptsas_delete_expander_phys(ioc);
2432 mptsas_probe_hba_phys(ioc);
2433 while (!mptsas_probe_expander_phys(ioc, &handle))
2434 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002435 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002436}
2437
2438/*
2439 * Work queue thread to handle Runtime discovery
2440 * Mere purpose is the hot add/delete of expanders
2441 *(Mutex LOCKED)
2442 */
2443static void
David Howellsc4028952006-11-22 14:57:56 +00002444mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002445{
David Howellsc4028952006-11-22 14:57:56 +00002446 struct mptsas_discovery_event *ev =
2447 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002448 MPT_ADAPTER *ioc = ev->ioc;
2449
2450 mutex_lock(&ioc->sas_discovery_mutex);
2451 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002452 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002453 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002454}
2455
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002456static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002457mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002458{
2459 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002460 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002461 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002462
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002463 mutex_lock(&ioc->sas_topology_mutex);
2464 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2465 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002466 if (!mptsas_is_end_device(
2467 &port_info->phy_info[i].attached))
2468 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002469 if (port_info->phy_info[i].attached.sas_address
2470 != sas_address)
2471 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002472 phy_info = &port_info->phy_info[i];
2473 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002474 }
2475 }
2476 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002477 return phy_info;
2478}
2479
2480static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002481mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002482{
2483 struct mptsas_portinfo *port_info;
2484 struct mptsas_phyinfo *phy_info = NULL;
2485 int i;
2486
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002487 mutex_lock(&ioc->sas_topology_mutex);
2488 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002489 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002490 if (!mptsas_is_end_device(
2491 &port_info->phy_info[i].attached))
2492 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002493 if (port_info->phy_info[i].attached.id != id)
2494 continue;
2495 if (port_info->phy_info[i].attached.channel != channel)
2496 continue;
2497 phy_info = &port_info->phy_info[i];
2498 break;
2499 }
2500 }
2501 mutex_unlock(&ioc->sas_topology_mutex);
2502 return phy_info;
2503}
2504
2505static struct mptsas_phyinfo *
2506mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2507{
2508 struct mptsas_portinfo *port_info;
2509 struct mptsas_phyinfo *phy_info = NULL;
2510 int i;
2511
2512 mutex_lock(&ioc->sas_topology_mutex);
2513 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2514 for (i = 0; i < port_info->num_phys; i++) {
2515 if (!mptsas_is_end_device(
2516 &port_info->phy_info[i].attached))
2517 continue;
2518 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2519 continue;
2520 if (port_info->phy_info[i].attached.phys_disk_num != id)
2521 continue;
2522 if (port_info->phy_info[i].attached.channel != channel)
2523 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002524 phy_info = &port_info->phy_info[i];
2525 break;
2526 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002527 }
2528 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002529 return phy_info;
2530}
2531
Moore, Eric4b766472006-03-14 09:14:12 -07002532/*
2533 * Work queue thread to clear the persitency table
2534 */
2535static void
David Howellsc4028952006-11-22 14:57:56 +00002536mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002537{
David Howellsc4028952006-11-22 14:57:56 +00002538 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002539
2540 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2541}
2542
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002543static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002544mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2545{
Eric Mooref99be432007-01-04 20:46:54 -07002546 int rc;
2547
Moore, Ericf44e5462006-03-14 09:14:21 -07002548 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002549 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002550}
2551
2552static void
2553mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2554{
2555 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2556 mptsas_reprobe_lun);
2557}
2558
Eric Mooreb506ade2007-01-29 09:45:37 -07002559static void
2560mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2561{
2562 CONFIGPARMS cfg;
2563 ConfigPageHeader_t hdr;
2564 dma_addr_t dma_handle;
2565 pRaidVolumePage0_t buffer = NULL;
2566 RaidPhysDiskPage0_t phys_disk;
2567 int i;
2568 struct mptsas_hotplug_event *ev;
2569
2570 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2571 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2572 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2573 cfg.pageAddr = (channel << 8) + id;
2574 cfg.cfghdr.hdr = &hdr;
2575 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2576
2577 if (mpt_config(ioc, &cfg) != 0)
2578 goto out;
2579
2580 if (!hdr.PageLength)
2581 goto out;
2582
2583 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2584 &dma_handle);
2585
2586 if (!buffer)
2587 goto out;
2588
2589 cfg.physAddr = dma_handle;
2590 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2591
2592 if (mpt_config(ioc, &cfg) != 0)
2593 goto out;
2594
2595 if (!(buffer->VolumeStatus.Flags &
2596 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2597 goto out;
2598
2599 if (!buffer->NumPhysDisks)
2600 goto out;
2601
2602 for (i = 0; i < buffer->NumPhysDisks; i++) {
2603
2604 if (mpt_raid_phys_disk_pg0(ioc,
2605 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2606 continue;
2607
2608 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2609 if (!ev) {
2610 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2611 goto out;
2612 }
2613
2614 INIT_WORK(&ev->work, mptsas_hotplug_work);
2615 ev->ioc = ioc;
2616 ev->id = phys_disk.PhysDiskID;
2617 ev->channel = phys_disk.PhysDiskBus;
2618 ev->phys_disk_num_valid = 1;
2619 ev->phys_disk_num = phys_disk.PhysDiskNum;
2620 ev->event_type = MPTSAS_ADD_DEVICE;
2621 schedule_work(&ev->work);
2622 }
2623
2624 out:
2625 if (buffer)
2626 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2627 dma_handle);
2628}
Moore, Erice6b2d762006-03-14 09:14:24 -07002629/*
2630 * Work queue thread to handle SAS hotplug events
2631 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002632static void
David Howellsc4028952006-11-22 14:57:56 +00002633mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002634{
David Howellsc4028952006-11-22 14:57:56 +00002635 struct mptsas_hotplug_event *ev =
2636 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002637
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002638 MPT_ADAPTER *ioc = ev->ioc;
2639 struct mptsas_phyinfo *phy_info;
2640 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002641 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002642 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002643 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002644 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002645 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002646 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002647 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002648 VirtDevice *vdevice;
2649
Moore, Erice6b2d762006-03-14 09:14:24 -07002650 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002651 switch (ev->event_type) {
2652 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002653
Eric Mooreb506ade2007-01-29 09:45:37 -07002654 phy_info = NULL;
2655 if (ev->phys_disk_num_valid) {
2656 if (ev->hidden_raid_component){
2657 if (mptsas_sas_device_pg0(ioc, &sas_device,
2658 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2659 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2660 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302661 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002662 "%s: exit at line=%d\n", ioc->name,
2663 __FUNCTION__, __LINE__));
2664 break;
2665 }
2666 phy_info = mptsas_find_phyinfo_by_sas_address(
2667 ioc, sas_device.sas_address);
2668 }else
2669 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2670 ioc, ev->channel, ev->phys_disk_num);
2671 }
2672
2673 if (!phy_info)
2674 phy_info = mptsas_find_phyinfo_by_target(ioc,
2675 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002676
Moore, Ericf44e5462006-03-14 09:14:21 -07002677 /*
2678 * Sanity checks, for non-existing phys and remote rphys.
2679 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002680 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302681 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002682 "%s: exit at line=%d\n", ioc->name,
2683 __FUNCTION__, __LINE__));
2684 break;
2685 }
2686 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302687 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002688 "%s: exit at line=%d\n", ioc->name,
2689 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002690 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002691 }
2692 rphy = mptsas_get_rphy(phy_info);
2693 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302694 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002695 "%s: exit at line=%d\n", ioc->name,
2696 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002697 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002698 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002699
Eric Moore547f9a22006-06-27 14:42:12 -06002700 port = mptsas_get_port(phy_info);
2701 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302702 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002703 "%s: exit at line=%d\n", ioc->name,
2704 __FUNCTION__, __LINE__));
2705 break;
2706 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002707
Eric Moore547f9a22006-06-27 14:42:12 -06002708 starget = mptsas_get_starget(phy_info);
2709 if (starget) {
2710 vtarget = starget->hostdata;
2711
2712 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302713 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002714 "%s: exit at line=%d\n", ioc->name,
2715 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002716 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002717 }
2718
Moore, Ericf44e5462006-03-14 09:14:21 -07002719 /*
2720 * Handling RAID components
2721 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002722 if (ev->phys_disk_num_valid &&
2723 ev->hidden_raid_component) {
2724 printk(MYIOC_s_INFO_FMT
2725 "RAID Hidding: channel=%d, id=%d, "
2726 "physdsk %d \n", ioc->name, ev->channel,
2727 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002728 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002729 vtarget->tflags |=
2730 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002731 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002732 phy_info->attached.phys_disk_num =
2733 ev->phys_disk_num;
2734 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002735 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002736 }
2737
Eric Mooreb506ade2007-01-29 09:45:37 -07002738 if (phy_info->attached.device_info &
2739 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002740 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002741 if (phy_info->attached.device_info &
2742 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002743 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002744 if (phy_info->attached.device_info &
2745 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002746 ds = "sata";
2747
2748 printk(MYIOC_s_INFO_FMT
2749 "removing %s device, channel %d, id %d, phy %d\n",
2750 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Mooredc22f162006-07-06 11:23:14 -06002751 dev_printk(KERN_DEBUG, &port->dev,
2752 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002753 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302754 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002755 break;
2756 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002757
Moore, Ericbd23e942006-04-17 12:43:04 -06002758 if (ev->phys_disk_num_valid)
2759 mpt_findImVolumes(ioc);
2760
Moore, Ericc73787ee2006-01-26 16:20:06 -07002761 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002762 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002763 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002764 if (mptsas_sas_device_pg0(ioc, &sas_device,
2765 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002766 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2767 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302768 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002769 "%s: exit at line=%d\n", ioc->name,
2770 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002771 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002772 }
2773
Eric Moore547f9a22006-06-27 14:42:12 -06002774 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002775
Eric Moore547f9a22006-06-27 14:42:12 -06002776 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2777 sas_device.sas_address);
2778
2779 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302780 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002781 "%s: exit at line=%d\n", ioc->name,
2782 __FUNCTION__, __LINE__));
2783 break;
2784 }
2785
2786 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002787 if (starget && (!ev->hidden_raid_component)){
2788
Eric Moore547f9a22006-06-27 14:42:12 -06002789 vtarget = starget->hostdata;
2790
2791 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302792 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002793 "%s: exit at line=%d\n", ioc->name,
2794 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002795 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002796 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002797 /*
2798 * Handling RAID components
2799 */
2800 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002801 printk(MYIOC_s_INFO_FMT
2802 "RAID Exposing: channel=%d, id=%d, "
2803 "physdsk %d \n", ioc->name, ev->channel,
2804 ev->id, ev->phys_disk_num);
2805 vtarget->tflags &=
2806 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002807 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002808 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002809 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002810 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002811 break;
2812 }
2813
Eric Moore547f9a22006-06-27 14:42:12 -06002814 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302815 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002816 "%s: exit at line=%d\n", ioc->name,
2817 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002818 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002819 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002820 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002821
Eric Moore547f9a22006-06-27 14:42:12 -06002822 port = mptsas_get_port(phy_info);
2823 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302824 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002825 "%s: exit at line=%d\n", ioc->name,
2826 __FUNCTION__, __LINE__));
2827 break;
2828 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002829 memcpy(&phy_info->attached, &sas_device,
2830 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002831
Eric Mooreb506ade2007-01-29 09:45:37 -07002832 if (phy_info->attached.device_info &
2833 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002834 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002835 if (phy_info->attached.device_info &
2836 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002837 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002838 if (phy_info->attached.device_info &
2839 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002840 ds = "sata";
2841
2842 printk(MYIOC_s_INFO_FMT
2843 "attaching %s device, channel %d, id %d, phy %d\n",
2844 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2845
James Bottomleyf013db32006-03-18 14:54:36 -06002846 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002847 rphy = sas_end_device_alloc(port);
2848 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302849 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002850 "%s: exit at line=%d\n", ioc->name,
2851 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002852 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002853 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002854
James Bottomleyf013db32006-03-18 14:54:36 -06002855 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002856 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302857 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002858 "%s: exit at line=%d\n", ioc->name,
2859 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002860 sas_rphy_free(rphy);
2861 break;
2862 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302863 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002864 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002865 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002866 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2867 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002868 if (sdev) {
2869 scsi_device_put(sdev);
2870 break;
2871 }
2872 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002873 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002874 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2875 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002876 mpt_findImVolumes(ioc);
2877 break;
2878 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002879 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002880 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002881 if (!sdev)
2882 break;
2883 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002884 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002885 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002886 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002887 scsi_remove_device(sdev);
2888 scsi_device_put(sdev);
2889 mpt_findImVolumes(ioc);
2890 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002891 case MPTSAS_ADD_INACTIVE_VOLUME:
2892 mptsas_adding_inactive_raid_components(ioc,
2893 ev->channel, ev->id);
2894 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002895 case MPTSAS_IGNORE_EVENT:
2896 default:
2897 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002898 }
2899
Moore, Erice6b2d762006-03-14 09:14:24 -07002900 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002901 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002902}
2903
2904static void
Eric Moore547f9a22006-06-27 14:42:12 -06002905mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002906 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2907{
2908 struct mptsas_hotplug_event *ev;
2909 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2910 __le64 sas_address;
2911
2912 if ((device_info &
2913 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2914 MPI_SAS_DEVICE_INFO_STP_TARGET |
2915 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2916 return;
2917
Moore, Eric4b766472006-03-14 09:14:12 -07002918 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002919 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002920
2921 mptsas_target_reset_queue(ioc, sas_event_data);
2922 break;
2923
2924 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002925 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002926 if (!ev) {
2927 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2928 break;
2929 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002930
David Howellsc4028952006-11-22 14:57:56 +00002931 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002932 ev->ioc = ioc;
2933 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2934 ev->parent_handle =
2935 le16_to_cpu(sas_event_data->ParentDevHandle);
2936 ev->channel = sas_event_data->Bus;
2937 ev->id = sas_event_data->TargetID;
2938 ev->phy_id = sas_event_data->PhyNum;
2939 memcpy(&sas_address, &sas_event_data->SASAddress,
2940 sizeof(__le64));
2941 ev->sas_address = le64_to_cpu(sas_address);
2942 ev->device_info = device_info;
2943
2944 if (sas_event_data->ReasonCode &
2945 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2946 ev->event_type = MPTSAS_ADD_DEVICE;
2947 else
2948 ev->event_type = MPTSAS_DEL_DEVICE;
2949 schedule_work(&ev->work);
2950 break;
2951 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2952 /*
2953 * Persistent table is full.
2954 */
Eric Moore547f9a22006-06-27 14:42:12 -06002955 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002956 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002957 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002958 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002959 /*
2960 * TODO, handle other events
2961 */
Moore, Eric4b766472006-03-14 09:14:12 -07002962 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002963 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002964 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002965 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2966 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2967 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2968 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002969 default:
2970 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002971 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002972}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002973static void
Eric Moore547f9a22006-06-27 14:42:12 -06002974mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002975 EVENT_DATA_RAID *raid_event_data)
2976{
2977 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002978 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2979 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002980
2981 if (ioc->bus_type != SAS)
2982 return;
2983
Eric Moore547f9a22006-06-27 14:42:12 -06002984 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002985 if (!ev) {
2986 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2987 return;
2988 }
2989
David Howellsc4028952006-11-22 14:57:56 +00002990 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002991 ev->ioc = ioc;
2992 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002993 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002994 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002995
2996 switch (raid_event_data->ReasonCode) {
2997 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002998 ev->phys_disk_num_valid = 1;
2999 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003000 ev->event_type = MPTSAS_ADD_DEVICE;
3001 break;
3002 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07003003 ev->phys_disk_num_valid = 1;
3004 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003005 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003006 ev->event_type = MPTSAS_DEL_DEVICE;
3007 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003008 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3009 switch (state) {
3010 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003011 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06003012 ev->phys_disk_num_valid = 1;
3013 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003014 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06003015 ev->event_type = MPTSAS_ADD_DEVICE;
3016 break;
3017 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003018 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3019 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3020 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07003021 ev->phys_disk_num_valid = 1;
3022 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06003023 ev->event_type = MPTSAS_DEL_DEVICE;
3024 break;
3025 default:
3026 break;
3027 }
3028 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003029 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
3030 ev->event_type = MPTSAS_DEL_RAID;
3031 break;
3032 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
3033 ev->event_type = MPTSAS_ADD_RAID;
3034 break;
3035 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003036 switch (state) {
3037 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3038 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
3039 ev->event_type = MPTSAS_DEL_RAID;
3040 break;
3041 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3042 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
3043 ev->event_type = MPTSAS_ADD_RAID;
3044 break;
3045 default:
3046 break;
3047 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003048 break;
3049 default:
3050 break;
3051 }
3052 schedule_work(&ev->work);
3053}
3054
Moore, Erice6b2d762006-03-14 09:14:24 -07003055static void
Eric Moore547f9a22006-06-27 14:42:12 -06003056mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003057 EVENT_DATA_SAS_DISCOVERY *discovery_data)
3058{
3059 struct mptsas_discovery_event *ev;
3060
3061 /*
3062 * DiscoveryStatus
3063 *
3064 * This flag will be non-zero when firmware
3065 * kicks off discovery, and return to zero
3066 * once its completed.
3067 */
3068 if (discovery_data->DiscoveryStatus)
3069 return;
3070
Eric Moore547f9a22006-06-27 14:42:12 -06003071 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003072 if (!ev)
3073 return;
David Howellsc4028952006-11-22 14:57:56 +00003074 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003075 ev->ioc = ioc;
3076 schedule_work(&ev->work);
3077};
3078
Eric Mooreb506ade2007-01-29 09:45:37 -07003079/*
3080 * mptsas_send_ir2_event - handle exposing hidden disk when
3081 * an inactive raid volume is added
3082 *
3083 * @ioc: Pointer to MPT_ADAPTER structure
3084 * @ir2_data
3085 *
3086 */
3087static void
3088mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3089{
3090 struct mptsas_hotplug_event *ev;
3091
3092 if (ir2_data->ReasonCode !=
3093 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3094 return;
3095
3096 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3097 if (!ev)
3098 return;
3099
3100 INIT_WORK(&ev->work, mptsas_hotplug_work);
3101 ev->ioc = ioc;
3102 ev->id = ir2_data->TargetID;
3103 ev->channel = ir2_data->Bus;
3104 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3105
3106 schedule_work(&ev->work);
3107};
Moore, Erice6b2d762006-03-14 09:14:24 -07003108
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003109static int
3110mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3111{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003112 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003113 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3114
3115 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003116 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003117
Moore, Erice6b2d762006-03-14 09:14:24 -07003118 /*
3119 * sas_discovery_ignore_events
3120 *
3121 * This flag is to prevent anymore processing of
3122 * sas events once mptsas_remove function is called.
3123 */
3124 if (ioc->sas_discovery_ignore_events) {
3125 rc = mptscsih_event_process(ioc, reply);
3126 goto out;
3127 }
3128
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003129 switch (event) {
3130 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003131 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003132 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003133 break;
3134 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003135 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003136 (EVENT_DATA_RAID *)reply->Data);
3137 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003138 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003139 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003140 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003141 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003142 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003143 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003144 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003145 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3146 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003147 case MPI_EVENT_IR2:
3148 mptsas_send_ir2_event(ioc,
3149 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3150 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003151 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003152 rc = mptscsih_event_process(ioc, reply);
3153 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003154 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003155 out:
3156
3157 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003158}
3159
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003160static int
3161mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3162{
3163 struct Scsi_Host *sh;
3164 MPT_SCSI_HOST *hd;
3165 MPT_ADAPTER *ioc;
3166 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003167 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003168 int numSGE = 0;
3169 int scale;
3170 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003171 int error=0;
3172 int r;
3173
3174 r = mpt_attach(pdev,id);
3175 if (r)
3176 return r;
3177
3178 ioc = pci_get_drvdata(pdev);
3179 ioc->DoneCtx = mptsasDoneCtx;
3180 ioc->TaskCtx = mptsasTaskCtx;
3181 ioc->InternalCtx = mptsasInternalCtx;
3182
3183 /* Added sanity check on readiness of the MPT adapter.
3184 */
3185 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3186 printk(MYIOC_s_WARN_FMT
3187 "Skipping because it's not operational!\n",
3188 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003189 error = -ENODEV;
3190 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003191 }
3192
3193 if (!ioc->active) {
3194 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3195 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003196 error = -ENODEV;
3197 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003198 }
3199
3200 /* Sanity check - ensure at least 1 port is INITIATOR capable
3201 */
3202 ioc_cap = 0;
3203 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3204 if (ioc->pfacts[ii].ProtocolFlags &
3205 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3206 ioc_cap++;
3207 }
3208
3209 if (!ioc_cap) {
3210 printk(MYIOC_s_WARN_FMT
3211 "Skipping ioc=%p because SCSI Initiator mode "
3212 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003213 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003214 }
3215
3216 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3217 if (!sh) {
3218 printk(MYIOC_s_WARN_FMT
3219 "Unable to register controller with SCSI subsystem\n",
3220 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003221 error = -1;
3222 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003223 }
3224
3225 spin_lock_irqsave(&ioc->FreeQlock, flags);
3226
3227 /* Attach the SCSI Host to the IOC structure
3228 */
3229 ioc->sh = sh;
3230
3231 sh->io_port = 0;
3232 sh->n_io_port = 0;
3233 sh->irq = 0;
3234
3235 /* set 16 byte cdb's */
3236 sh->max_cmd_len = 16;
3237
Eric Moore793955f2007-01-29 09:42:20 -07003238 sh->max_id = ioc->pfacts[0].PortSCSIID;
3239 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003240
3241 sh->transportt = mptsas_transport_template;
3242
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243 sh->this_id = ioc->pfacts[0].PortSCSIID;
3244
3245 /* Required entry.
3246 */
3247 sh->unique_id = ioc->id;
3248
3249 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003250 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003251 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003252 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003253 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003254
3255 /* Verify that we won't exceed the maximum
3256 * number of chain buffers
3257 * We can optimize: ZZ = req_sz/sizeof(SGE)
3258 * For 32bit SGE's:
3259 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3260 * + (req_sz - 64)/sizeof(SGE)
3261 * A slightly different algorithm is required for
3262 * 64bit SGEs.
3263 */
3264 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3265 if (sizeof(dma_addr_t) == sizeof(u64)) {
3266 numSGE = (scale - 1) *
3267 (ioc->facts.MaxChainDepth-1) + scale +
3268 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3269 sizeof(u32));
3270 } else {
3271 numSGE = 1 + (scale - 1) *
3272 (ioc->facts.MaxChainDepth-1) + scale +
3273 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3274 sizeof(u32));
3275 }
3276
3277 if (numSGE < sh->sg_tablesize) {
3278 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303279 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003280 "Resetting sg_tablesize to %d from %d\n",
3281 ioc->name, numSGE, sh->sg_tablesize));
3282 sh->sg_tablesize = numSGE;
3283 }
3284
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003285 hd = (MPT_SCSI_HOST *) sh->hostdata;
3286 hd->ioc = ioc;
3287
3288 /* SCSI needs scsi_cmnd lookup table!
3289 * (with size equal to req_depth*PtrSz!)
3290 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003291 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3292 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003294 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003295 }
3296
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303297 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003298 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003299
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003300 /* Clear the TM flags
3301 */
3302 hd->tmPending = 0;
3303 hd->tmState = TM_STATE_NONE;
3304 hd->resetPending = 0;
3305 hd->abortSCpnt = NULL;
3306
3307 /* Clear the pointer used to store
3308 * single-threaded commands, i.e., those
3309 * issued during a bus scan, dv and
3310 * configuration pages.
3311 */
3312 hd->cmdPtr = NULL;
3313
3314 /* Initialize this SCSI Hosts' timers
3315 * To use, set the timer expires field
3316 * and add_timer
3317 */
3318 init_timer(&hd->timer);
3319 hd->timer.data = (unsigned long) hd;
3320 hd->timer.function = mptscsih_timer_expired;
3321
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003322 ioc->sas_data.ptClear = mpt_pt_clear;
3323
Eric Mooredf9e0622007-01-29 09:46:21 -07003324 init_waitqueue_head(&hd->scandv_waitq);
3325 hd->scandv_wait_done = 0;
3326 hd->last_queue_full = 0;
3327 INIT_LIST_HEAD(&hd->target_reset_list);
3328 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3329
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003330 if (ioc->sas_data.ptClear==1) {
3331 mptbase_sas_persist_operation(
3332 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3333 }
3334
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003335 error = scsi_add_host(sh, &ioc->pcidev->dev);
3336 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303337 dprintk(ioc, printk(KERN_ERR MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003338 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003339 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003340 }
3341
3342 mptsas_scan_sas_topology(ioc);
3343
3344 return 0;
3345
Eric Moore547f9a22006-06-27 14:42:12 -06003346 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003347
3348 mptscsih_remove(pdev);
3349 return error;
3350}
3351
3352static void __devexit mptsas_remove(struct pci_dev *pdev)
3353{
3354 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3355 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003356 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003357
Eric Mooreb506ade2007-01-29 09:45:37 -07003358 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003359 sas_remove_host(ioc->sh);
3360
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003361 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003362 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3363 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003364 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303365 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003366 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003367 kfree(p);
3368 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003369 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003370
3371 mptscsih_remove(pdev);
3372}
3373
3374static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003375 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003376 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003377 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003378 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003379 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003380 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003381 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003382 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003383 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003384 PCI_ANY_ID, PCI_ANY_ID },
3385 {0} /* Terminating entry */
3386};
3387MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3388
3389
3390static struct pci_driver mptsas_driver = {
3391 .name = "mptsas",
3392 .id_table = mptsas_pci_table,
3393 .probe = mptsas_probe,
3394 .remove = __devexit_p(mptsas_remove),
3395 .shutdown = mptscsih_shutdown,
3396#ifdef CONFIG_PM
3397 .suspend = mptscsih_suspend,
3398 .resume = mptscsih_resume,
3399#endif
3400};
3401
3402static int __init
3403mptsas_init(void)
3404{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303405 int error;
3406
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003407 show_mptmod_ver(my_NAME, my_VERSION);
3408
3409 mptsas_transport_template =
3410 sas_attach_transport(&mptsas_transport_functions);
3411 if (!mptsas_transport_template)
3412 return -ENODEV;
3413
3414 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003415 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003416 mptsasInternalCtx =
3417 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003418 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003419
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303420 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3421 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003422
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303423 error = pci_register_driver(&mptsas_driver);
3424 if (error)
3425 sas_release_transport(mptsas_transport_template);
3426
3427 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003428}
3429
3430static void __exit
3431mptsas_exit(void)
3432{
3433 pci_unregister_driver(&mptsas_driver);
3434 sas_release_transport(mptsas_transport_template);
3435
3436 mpt_reset_deregister(mptsasDoneCtx);
3437 mpt_event_deregister(mptsasDoneCtx);
3438
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003439 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003440 mpt_deregister(mptsasInternalCtx);
3441 mpt_deregister(mptsasTaskCtx);
3442 mpt_deregister(mptsasDoneCtx);
3443}
3444
3445module_init(mptsas_init);
3446module_exit(mptsas_exit);