blob: b9c69bff218caed8ac8dd2057157d7c72aa31818 [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
Christoph Hellwig0c33b272005-09-09 16:27:19 +020092static int mptsasDoneCtx = -1;
93static int mptsasTaskCtx = -1;
94static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020095static int mptsasMgmtCtx = -1;
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
626 if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
627 sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
628 mpt_free_msg_frame(ioc, mf);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530629 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700630 ioc->name,__FUNCTION__, __LINE__));
631 return 0;
632 }
633
634 return 1;
635}
636
637/**
638 * mptsas_target_reset_queue
639 *
640 * Receive request for TARGET_RESET after recieving an firmware
641 * event NOT_RESPONDING_EVENT, then put command in link list
642 * and queue if task_queue already in use.
643 *
644 * @ioc
645 * @sas_event_data
646 *
647 **/
648static void
649mptsas_target_reset_queue(MPT_ADAPTER *ioc,
650 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
651{
652 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
653 VirtTarget *vtarget = NULL;
654 struct mptsas_target_reset_event *target_reset_list;
655 u8 id, channel;
656
657 id = sas_event_data->TargetID;
658 channel = sas_event_data->Bus;
659
660 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
661 return;
662
663 vtarget->deleted = 1; /* block IO */
664
665 target_reset_list = kzalloc(sizeof(*target_reset_list),
666 GFP_ATOMIC);
667 if (!target_reset_list) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530668 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700669 ioc->name,__FUNCTION__, __LINE__));
670 return;
671 }
672
673 memcpy(&target_reset_list->sas_event_data, sas_event_data,
674 sizeof(*sas_event_data));
675 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
676
677 if (hd->resetPending)
678 return;
679
680 if (mptsas_target_reset(ioc, channel, id)) {
681 target_reset_list->target_reset_issued = 1;
682 hd->resetPending = 1;
683 }
684}
685
686/**
687 * mptsas_dev_reset_complete
688 *
689 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
690 * enable work queue to finish off removing device from upper layers.
691 * then send next TARGET_RESET in the queue.
692 *
693 * @ioc
694 *
695 **/
696static void
697mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
698{
699 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
700 struct list_head *head = &hd->target_reset_list;
701 struct mptsas_target_reset_event *target_reset_list;
702 struct mptsas_hotplug_event *ev;
703 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
704 u8 id, channel;
705 __le64 sas_address;
706
707 if (list_empty(head))
708 return;
709
710 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
711
712 sas_event_data = &target_reset_list->sas_event_data;
713 id = sas_event_data->TargetID;
714 channel = sas_event_data->Bus;
715 hd->resetPending = 0;
716
717 /*
718 * retry target reset
719 */
720 if (!target_reset_list->target_reset_issued) {
721 if (mptsas_target_reset(ioc, channel, id)) {
722 target_reset_list->target_reset_issued = 1;
723 hd->resetPending = 1;
724 }
725 return;
726 }
727
728 /*
729 * enable work queue to remove device from upper layers
730 */
731 list_del(&target_reset_list->list);
732
733 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
734 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530735 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700736 ioc->name,__FUNCTION__, __LINE__));
737 return;
738 }
739
740 INIT_WORK(&ev->work, mptsas_hotplug_work);
741 ev->ioc = ioc;
742 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
743 ev->parent_handle =
744 le16_to_cpu(sas_event_data->ParentDevHandle);
745 ev->channel = channel;
746 ev->id =id;
747 ev->phy_id = sas_event_data->PhyNum;
748 memcpy(&sas_address, &sas_event_data->SASAddress,
749 sizeof(__le64));
750 ev->sas_address = le64_to_cpu(sas_address);
751 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
752 ev->event_type = MPTSAS_DEL_DEVICE;
753 schedule_work(&ev->work);
754 kfree(target_reset_list);
755
756 /*
757 * issue target reset to next device in the queue
758 */
759
760 head = &hd->target_reset_list;
761 if (list_empty(head))
762 return;
763
764 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
765 list);
766
767 sas_event_data = &target_reset_list->sas_event_data;
768 id = sas_event_data->TargetID;
769 channel = sas_event_data->Bus;
770
771 if (mptsas_target_reset(ioc, channel, id)) {
772 target_reset_list->target_reset_issued = 1;
773 hd->resetPending = 1;
774 }
775}
776
777/**
778 * mptsas_taskmgmt_complete
779 *
780 * @ioc
781 * @mf
782 * @mr
783 *
784 **/
785static int
786mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
787{
788 mptsas_dev_reset_complete(ioc);
789 return mptscsih_taskmgmt_complete(ioc, mf, mr);
790}
791
792/**
793 * mptscsih_ioc_reset
794 *
795 * @ioc
796 * @reset_phase
797 *
798 **/
799static int
800mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
801{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800802 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700803 struct mptsas_target_reset_event *target_reset_list, *n;
804 int rc;
805
806 rc = mptscsih_ioc_reset(ioc, reset_phase);
807
808 if (ioc->bus_type != SAS)
809 goto out;
810
811 if (reset_phase != MPT_IOC_POST_RESET)
812 goto out;
813
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800814 if (!ioc->sh || !ioc->sh->hostdata)
815 goto out;
816 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
817 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700818 goto out;
819
820 if (list_empty(&hd->target_reset_list))
821 goto out;
822
823 /* flush the target_reset_list */
824 list_for_each_entry_safe(target_reset_list, n,
825 &hd->target_reset_list, list) {
826 list_del(&target_reset_list->list);
827 kfree(target_reset_list);
828 }
829
830 out:
831 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600832}
833
Christoph Hellwige3094442006-02-16 13:25:36 +0100834static int
Moore, Eric52435432006-03-14 09:14:15 -0700835mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100836 u32 form, u32 form_specific)
837{
838 ConfigExtendedPageHeader_t hdr;
839 CONFIGPARMS cfg;
840 SasEnclosurePage0_t *buffer;
841 dma_addr_t dma_handle;
842 int error;
843 __le64 le_identifier;
844
845 memset(&hdr, 0, sizeof(hdr));
846 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
847 hdr.PageNumber = 0;
848 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
849 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
850
851 cfg.cfghdr.ehdr = &hdr;
852 cfg.physAddr = -1;
853 cfg.pageAddr = form + form_specific;
854 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
855 cfg.dir = 0; /* read */
856 cfg.timeout = 10;
857
858 error = mpt_config(ioc, &cfg);
859 if (error)
860 goto out;
861 if (!hdr.ExtPageLength) {
862 error = -ENXIO;
863 goto out;
864 }
865
866 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
867 &dma_handle);
868 if (!buffer) {
869 error = -ENOMEM;
870 goto out;
871 }
872
873 cfg.physAddr = dma_handle;
874 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
875
876 error = mpt_config(ioc, &cfg);
877 if (error)
878 goto out_free_consistent;
879
880 /* save config data */
881 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
882 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
883 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
884 enclosure->flags = le16_to_cpu(buffer->Flags);
885 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
886 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
887 enclosure->start_id = buffer->StartTargetID;
888 enclosure->start_channel = buffer->StartBus;
889 enclosure->sep_id = buffer->SEPTargetID;
890 enclosure->sep_channel = buffer->SEPBus;
891
892 out_free_consistent:
893 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
894 buffer, dma_handle);
895 out:
896 return error;
897}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200898
James Bottomleyf013db32006-03-18 14:54:36 -0600899static int
900mptsas_slave_configure(struct scsi_device *sdev)
901{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600902
James Bottomleye8bf3942006-07-11 17:49:34 -0400903 if (sdev->channel == MPTSAS_RAID_CHANNEL)
904 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600905
James Bottomleye8bf3942006-07-11 17:49:34 -0400906 sas_read_port_mode_page(sdev);
907
908 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600909 return mptscsih_slave_configure(sdev);
910}
911
Eric Moore547f9a22006-06-27 14:42:12 -0600912static int
913mptsas_target_alloc(struct scsi_target *starget)
914{
915 struct Scsi_Host *host = dev_to_shost(&starget->dev);
916 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
917 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700918 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600919 struct sas_rphy *rphy;
920 struct mptsas_portinfo *p;
921 int i;
922
923 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
924 if (!vtarget)
925 return -ENOMEM;
926
927 vtarget->starget = starget;
928 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700929 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
930 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600931 channel = 0;
932
Eric Moore793955f2007-01-29 09:42:20 -0700933 /*
934 * RAID volumes placed beyond the last expected port.
935 */
936 if (starget->channel == MPTSAS_RAID_CHANNEL) {
937 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
938 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
939 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600940 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700941 }
Eric Moore547f9a22006-06-27 14:42:12 -0600942
943 rphy = dev_to_rphy(starget->dev.parent);
944 mutex_lock(&hd->ioc->sas_topology_mutex);
945 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
946 for (i = 0; i < p->num_phys; i++) {
947 if (p->phy_info[i].attached.sas_address !=
948 rphy->identify.sas_address)
949 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700950 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600951 channel = p->phy_info[i].attached.channel;
952 mptsas_set_starget(&p->phy_info[i], starget);
953
954 /*
955 * Exposing hidden raid components
956 */
Eric Moore793955f2007-01-29 09:42:20 -0700957 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
958 id = mptscsih_raid_id_to_num(hd->ioc,
959 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600960 vtarget->tflags |=
961 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700962 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600963 }
964 mutex_unlock(&hd->ioc->sas_topology_mutex);
965 goto out;
966 }
967 }
968 mutex_unlock(&hd->ioc->sas_topology_mutex);
969
970 kfree(vtarget);
971 return -ENXIO;
972
973 out:
Eric Moore793955f2007-01-29 09:42:20 -0700974 vtarget->id = id;
975 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600976 starget->hostdata = vtarget;
977 return 0;
978}
979
980static void
981mptsas_target_destroy(struct scsi_target *starget)
982{
983 struct Scsi_Host *host = dev_to_shost(&starget->dev);
984 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
985 struct sas_rphy *rphy;
986 struct mptsas_portinfo *p;
987 int i;
988
989 if (!starget->hostdata)
990 return;
991
James Bottomleye8bf3942006-07-11 17:49:34 -0400992 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600993 goto out;
994
995 rphy = dev_to_rphy(starget->dev.parent);
996 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
997 for (i = 0; i < p->num_phys; i++) {
998 if (p->phy_info[i].attached.sas_address !=
999 rphy->identify.sas_address)
1000 continue;
1001 mptsas_set_starget(&p->phy_info[i], NULL);
1002 goto out;
1003 }
1004 }
1005
1006 out:
1007 kfree(starget->hostdata);
1008 starget->hostdata = NULL;
1009}
1010
1011
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001012static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001013mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001014{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001015 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001016 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1017 struct sas_rphy *rphy;
1018 struct mptsas_portinfo *p;
1019 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001020 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001021 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001022
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001023 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001024 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -06001025 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001026 hd->ioc->name, sizeof(VirtDevice));
1027 return -ENOMEM;
1028 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001029 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -06001030 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001031
James Bottomleye8bf3942006-07-11 17:49:34 -04001032 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001033 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001034
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001035 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001036 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001037 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1038 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001039 if (p->phy_info[i].attached.sas_address !=
1040 rphy->identify.sas_address)
1041 continue;
1042 vdev->lun = sdev->lun;
1043 /*
1044 * Exposing hidden raid components
1045 */
1046 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001047 p->phy_info[i].attached.channel,
1048 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001049 sdev->no_uld_attach = 1;
1050 mutex_unlock(&hd->ioc->sas_topology_mutex);
1051 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001052 }
1053 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001054 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001055
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001056 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001057 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001058
1059 out:
Eric Moore547f9a22006-06-27 14:42:12 -06001060 vdev->vtarget->num_luns++;
1061 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001062 return 0;
1063}
1064
Eric Moore547f9a22006-06-27 14:42:12 -06001065static int
1066mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001067{
Eric Moore547f9a22006-06-27 14:42:12 -06001068 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001069
Eric Moore793955f2007-01-29 09:42:20 -07001070 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001071 SCpnt->result = DID_NO_CONNECT << 16;
1072 done(SCpnt);
1073 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001074 }
Eric Moore547f9a22006-06-27 14:42:12 -06001075
Eric Moore793955f2007-01-29 09:42:20 -07001076// scsi_print_command(SCpnt);
1077
Eric Moore547f9a22006-06-27 14:42:12 -06001078 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001079}
1080
Eric Moore547f9a22006-06-27 14:42:12 -06001081
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001082static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001083 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001084 .proc_name = "mptsas",
1085 .proc_info = mptscsih_proc_info,
1086 .name = "MPT SPI Host",
1087 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001088 .queuecommand = mptsas_qcmd,
1089 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001090 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001091 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001092 .target_destroy = mptsas_target_destroy,
1093 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001094 .change_queue_depth = mptscsih_change_queue_depth,
1095 .eh_abort_handler = mptscsih_abort,
1096 .eh_device_reset_handler = mptscsih_dev_reset,
1097 .eh_bus_reset_handler = mptscsih_bus_reset,
1098 .eh_host_reset_handler = mptscsih_host_reset,
1099 .bios_param = mptscsih_bios_param,
1100 .can_queue = MPT_FC_CAN_QUEUE,
1101 .this_id = -1,
1102 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1103 .max_sectors = 8192,
1104 .cmd_per_lun = 7,
1105 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301106 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001107};
1108
Christoph Hellwigb5141122005-10-28 22:07:41 +02001109static int mptsas_get_linkerrors(struct sas_phy *phy)
1110{
1111 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1112 ConfigExtendedPageHeader_t hdr;
1113 CONFIGPARMS cfg;
1114 SasPhyPage1_t *buffer;
1115 dma_addr_t dma_handle;
1116 int error;
1117
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001118 /* FIXME: only have link errors on local phys */
1119 if (!scsi_is_sas_phy_local(phy))
1120 return -EINVAL;
1121
Christoph Hellwigb5141122005-10-28 22:07:41 +02001122 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1123 hdr.ExtPageLength = 0;
1124 hdr.PageNumber = 1 /* page number 1*/;
1125 hdr.Reserved1 = 0;
1126 hdr.Reserved2 = 0;
1127 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1128 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1129
1130 cfg.cfghdr.ehdr = &hdr;
1131 cfg.physAddr = -1;
1132 cfg.pageAddr = phy->identify.phy_identifier;
1133 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1134 cfg.dir = 0; /* read */
1135 cfg.timeout = 10;
1136
1137 error = mpt_config(ioc, &cfg);
1138 if (error)
1139 return error;
1140 if (!hdr.ExtPageLength)
1141 return -ENXIO;
1142
1143 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1144 &dma_handle);
1145 if (!buffer)
1146 return -ENOMEM;
1147
1148 cfg.physAddr = dma_handle;
1149 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1150
1151 error = mpt_config(ioc, &cfg);
1152 if (error)
1153 goto out_free_consistent;
1154
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301155 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001156
1157 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1158 phy->running_disparity_error_count =
1159 le32_to_cpu(buffer->RunningDisparityErrorCount);
1160 phy->loss_of_dword_sync_count =
1161 le32_to_cpu(buffer->LossDwordSynchCount);
1162 phy->phy_reset_problem_count =
1163 le32_to_cpu(buffer->PhyResetProblemCount);
1164
1165 out_free_consistent:
1166 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1167 buffer, dma_handle);
1168 return error;
1169}
1170
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001171static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1172 MPT_FRAME_HDR *reply)
1173{
1174 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1175 if (reply != NULL) {
1176 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1177 memcpy(ioc->sas_mgmt.reply, reply,
1178 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1179 }
1180 complete(&ioc->sas_mgmt.done);
1181 return 1;
1182}
1183
1184static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1185{
1186 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1187 SasIoUnitControlRequest_t *req;
1188 SasIoUnitControlReply_t *reply;
1189 MPT_FRAME_HDR *mf;
1190 MPIHeader_t *hdr;
1191 unsigned long timeleft;
1192 int error = -ERESTARTSYS;
1193
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001194 /* FIXME: fusion doesn't allow non-local phy reset */
1195 if (!scsi_is_sas_phy_local(phy))
1196 return -EINVAL;
1197
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001198 /* not implemented for expanders */
1199 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1200 return -ENXIO;
1201
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001202 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001203 goto out;
1204
1205 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1206 if (!mf) {
1207 error = -ENOMEM;
1208 goto out_unlock;
1209 }
1210
1211 hdr = (MPIHeader_t *) mf;
1212 req = (SasIoUnitControlRequest_t *)mf;
1213 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1214 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1215 req->MsgContext = hdr->MsgContext;
1216 req->Operation = hard_reset ?
1217 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1218 req->PhyNum = phy->identify.phy_identifier;
1219
1220 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1221
1222 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1223 10 * HZ);
1224 if (!timeleft) {
1225 /* On timeout reset the board */
1226 mpt_free_msg_frame(ioc, mf);
1227 mpt_HardResetHandler(ioc, CAN_SLEEP);
1228 error = -ETIMEDOUT;
1229 goto out_unlock;
1230 }
1231
1232 /* a reply frame is expected */
1233 if ((ioc->sas_mgmt.status &
1234 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1235 error = -ENXIO;
1236 goto out_unlock;
1237 }
1238
1239 /* process the completed Reply Message Frame */
1240 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1241 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1242 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1243 __FUNCTION__,
1244 reply->IOCStatus,
1245 reply->IOCLogInfo);
1246 error = -ENXIO;
1247 goto out_unlock;
1248 }
1249
1250 error = 0;
1251
1252 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001253 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001254 out:
1255 return error;
1256}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001257
Christoph Hellwige3094442006-02-16 13:25:36 +01001258static int
1259mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1260{
1261 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1262 int i, error;
1263 struct mptsas_portinfo *p;
1264 struct mptsas_enclosure enclosure_info;
1265 u64 enclosure_handle;
1266
1267 mutex_lock(&ioc->sas_topology_mutex);
1268 list_for_each_entry(p, &ioc->sas_topology, list) {
1269 for (i = 0; i < p->num_phys; i++) {
1270 if (p->phy_info[i].attached.sas_address ==
1271 rphy->identify.sas_address) {
1272 enclosure_handle = p->phy_info[i].
1273 attached.handle_enclosure;
1274 goto found_info;
1275 }
1276 }
1277 }
1278 mutex_unlock(&ioc->sas_topology_mutex);
1279 return -ENXIO;
1280
1281 found_info:
1282 mutex_unlock(&ioc->sas_topology_mutex);
1283 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001284 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001285 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1286 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1287 if (!error)
1288 *identifier = enclosure_info.enclosure_logical_id;
1289 return error;
1290}
1291
1292static int
1293mptsas_get_bay_identifier(struct sas_rphy *rphy)
1294{
1295 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1296 struct mptsas_portinfo *p;
1297 int i, rc;
1298
1299 mutex_lock(&ioc->sas_topology_mutex);
1300 list_for_each_entry(p, &ioc->sas_topology, list) {
1301 for (i = 0; i < p->num_phys; i++) {
1302 if (p->phy_info[i].attached.sas_address ==
1303 rphy->identify.sas_address) {
1304 rc = p->phy_info[i].attached.slot;
1305 goto out;
1306 }
1307 }
1308 }
1309 rc = -ENXIO;
1310 out:
1311 mutex_unlock(&ioc->sas_topology_mutex);
1312 return rc;
1313}
1314
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001315static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1316 struct request *req)
1317{
1318 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1319 MPT_FRAME_HDR *mf;
1320 SmpPassthroughRequest_t *smpreq;
1321 struct request *rsp = req->next_rq;
1322 int ret;
1323 int flagsLength;
1324 unsigned long timeleft;
1325 char *psge;
1326 dma_addr_t dma_addr_in = 0;
1327 dma_addr_t dma_addr_out = 0;
1328 u64 sas_address = 0;
1329
1330 if (!rsp) {
1331 printk(KERN_ERR "%s: the smp response space is missing\n",
1332 __FUNCTION__);
1333 return -EINVAL;
1334 }
1335
1336 /* do we need to support multiple segments? */
1337 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1338 printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
1339 __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1340 rsp->bio->bi_vcnt, rsp->data_len);
1341 return -EINVAL;
1342 }
1343
1344 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1345 if (ret)
1346 goto out;
1347
1348 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1349 if (!mf) {
1350 ret = -ENOMEM;
1351 goto out_unlock;
1352 }
1353
1354 smpreq = (SmpPassthroughRequest_t *)mf;
1355 memset(smpreq, 0, sizeof(*smpreq));
1356
1357 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1358 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1359
1360 if (rphy)
1361 sas_address = rphy->identify.sas_address;
1362 else {
1363 struct mptsas_portinfo *port_info;
1364
1365 mutex_lock(&ioc->sas_topology_mutex);
1366 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1367 if (port_info && port_info->phy_info)
1368 sas_address =
1369 port_info->phy_info[0].phy->identify.sas_address;
1370 mutex_unlock(&ioc->sas_topology_mutex);
1371 }
1372
1373 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1374
1375 psge = (char *)
1376 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1377
1378 /* request */
1379 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1380 MPI_SGE_FLAGS_END_OF_BUFFER |
1381 MPI_SGE_FLAGS_DIRECTION |
1382 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1383 flagsLength |= (req->data_len - 4);
1384
1385 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1386 req->data_len, PCI_DMA_BIDIRECTIONAL);
1387 if (!dma_addr_out)
1388 goto put_mf;
1389 mpt_add_sge(psge, flagsLength, dma_addr_out);
1390 psge += (sizeof(u32) + sizeof(dma_addr_t));
1391
1392 /* response */
1393 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1394 flagsLength |= rsp->data_len + 4;
1395 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1396 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1397 if (!dma_addr_in)
1398 goto unmap;
1399 mpt_add_sge(psge, flagsLength, dma_addr_in);
1400
1401 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1402
1403 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1404 if (!timeleft) {
1405 printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
1406 /* On timeout reset the board */
1407 mpt_HardResetHandler(ioc, CAN_SLEEP);
1408 ret = -ETIMEDOUT;
1409 goto unmap;
1410 }
1411 mf = NULL;
1412
1413 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1414 SmpPassthroughReply_t *smprep;
1415
1416 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1417 memcpy(req->sense, smprep, sizeof(*smprep));
1418 req->sense_len = sizeof(*smprep);
1419 } else {
1420 printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
1421 __FUNCTION__);
1422 ret = -ENXIO;
1423 }
1424unmap:
1425 if (dma_addr_out)
1426 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1427 PCI_DMA_BIDIRECTIONAL);
1428 if (dma_addr_in)
1429 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1430 PCI_DMA_BIDIRECTIONAL);
1431put_mf:
1432 if (mf)
1433 mpt_free_msg_frame(ioc, mf);
1434out_unlock:
1435 mutex_unlock(&ioc->sas_mgmt.mutex);
1436out:
1437 return ret;
1438}
1439
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001440static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001441 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001442 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1443 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001444 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001445 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001446};
1447
1448static struct scsi_transport_template *mptsas_transport_template;
1449
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001450static int
1451mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1452{
1453 ConfigExtendedPageHeader_t hdr;
1454 CONFIGPARMS cfg;
1455 SasIOUnitPage0_t *buffer;
1456 dma_addr_t dma_handle;
1457 int error, i;
1458
1459 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1460 hdr.ExtPageLength = 0;
1461 hdr.PageNumber = 0;
1462 hdr.Reserved1 = 0;
1463 hdr.Reserved2 = 0;
1464 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1465 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1466
1467 cfg.cfghdr.ehdr = &hdr;
1468 cfg.physAddr = -1;
1469 cfg.pageAddr = 0;
1470 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1471 cfg.dir = 0; /* read */
1472 cfg.timeout = 10;
1473
1474 error = mpt_config(ioc, &cfg);
1475 if (error)
1476 goto out;
1477 if (!hdr.ExtPageLength) {
1478 error = -ENXIO;
1479 goto out;
1480 }
1481
1482 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1483 &dma_handle);
1484 if (!buffer) {
1485 error = -ENOMEM;
1486 goto out;
1487 }
1488
1489 cfg.physAddr = dma_handle;
1490 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1491
1492 error = mpt_config(ioc, &cfg);
1493 if (error)
1494 goto out_free_consistent;
1495
1496 port_info->num_phys = buffer->NumPhys;
1497 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001498 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001499 if (!port_info->phy_info) {
1500 error = -ENOMEM;
1501 goto out_free_consistent;
1502 }
1503
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301504 ioc->nvdata_version_persistent =
1505 le16_to_cpu(buffer->NvdataVersionPersistent);
1506 ioc->nvdata_version_default =
1507 le16_to_cpu(buffer->NvdataVersionDefault);
1508
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001509 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301510 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001511 port_info->phy_info[i].phy_id = i;
1512 port_info->phy_info[i].port_id =
1513 buffer->PhyData[i].Port;
1514 port_info->phy_info[i].negotiated_link_rate =
1515 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001516 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001517 port_info->phy_info[i].handle =
1518 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001519 }
1520
1521 out_free_consistent:
1522 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1523 buffer, dma_handle);
1524 out:
1525 return error;
1526}
1527
1528static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301529mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1530{
1531 ConfigExtendedPageHeader_t hdr;
1532 CONFIGPARMS cfg;
1533 SasIOUnitPage1_t *buffer;
1534 dma_addr_t dma_handle;
1535 int error;
1536 u16 device_missing_delay;
1537
1538 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1539 memset(&cfg, 0, sizeof(CONFIGPARMS));
1540
1541 cfg.cfghdr.ehdr = &hdr;
1542 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1543 cfg.timeout = 10;
1544 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1545 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1546 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1547 cfg.cfghdr.ehdr->PageNumber = 1;
1548
1549 error = mpt_config(ioc, &cfg);
1550 if (error)
1551 goto out;
1552 if (!hdr.ExtPageLength) {
1553 error = -ENXIO;
1554 goto out;
1555 }
1556
1557 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1558 &dma_handle);
1559 if (!buffer) {
1560 error = -ENOMEM;
1561 goto out;
1562 }
1563
1564 cfg.physAddr = dma_handle;
1565 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1566
1567 error = mpt_config(ioc, &cfg);
1568 if (error)
1569 goto out_free_consistent;
1570
1571 ioc->io_missing_delay =
1572 le16_to_cpu(buffer->IODeviceMissingDelay);
1573 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1574 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1575 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1576 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1577
1578 out_free_consistent:
1579 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1580 buffer, dma_handle);
1581 out:
1582 return error;
1583}
1584
1585static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001586mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1587 u32 form, u32 form_specific)
1588{
1589 ConfigExtendedPageHeader_t hdr;
1590 CONFIGPARMS cfg;
1591 SasPhyPage0_t *buffer;
1592 dma_addr_t dma_handle;
1593 int error;
1594
1595 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1596 hdr.ExtPageLength = 0;
1597 hdr.PageNumber = 0;
1598 hdr.Reserved1 = 0;
1599 hdr.Reserved2 = 0;
1600 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1601 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1602
1603 cfg.cfghdr.ehdr = &hdr;
1604 cfg.dir = 0; /* read */
1605 cfg.timeout = 10;
1606
1607 /* Get Phy Pg 0 for each Phy. */
1608 cfg.physAddr = -1;
1609 cfg.pageAddr = form + form_specific;
1610 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1611
1612 error = mpt_config(ioc, &cfg);
1613 if (error)
1614 goto out;
1615
1616 if (!hdr.ExtPageLength) {
1617 error = -ENXIO;
1618 goto out;
1619 }
1620
1621 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1622 &dma_handle);
1623 if (!buffer) {
1624 error = -ENOMEM;
1625 goto out;
1626 }
1627
1628 cfg.physAddr = dma_handle;
1629 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1630
1631 error = mpt_config(ioc, &cfg);
1632 if (error)
1633 goto out_free_consistent;
1634
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301635 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001636
1637 phy_info->hw_link_rate = buffer->HwLinkRate;
1638 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1639 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1640 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1641
1642 out_free_consistent:
1643 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1644 buffer, dma_handle);
1645 out:
1646 return error;
1647}
1648
1649static int
1650mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1651 u32 form, u32 form_specific)
1652{
1653 ConfigExtendedPageHeader_t hdr;
1654 CONFIGPARMS cfg;
1655 SasDevicePage0_t *buffer;
1656 dma_addr_t dma_handle;
1657 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001658 int error=0;
1659
1660 if (ioc->sas_discovery_runtime &&
1661 mptsas_is_end_device(device_info))
1662 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001663
1664 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1665 hdr.ExtPageLength = 0;
1666 hdr.PageNumber = 0;
1667 hdr.Reserved1 = 0;
1668 hdr.Reserved2 = 0;
1669 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1670 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1671
1672 cfg.cfghdr.ehdr = &hdr;
1673 cfg.pageAddr = form + form_specific;
1674 cfg.physAddr = -1;
1675 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1676 cfg.dir = 0; /* read */
1677 cfg.timeout = 10;
1678
Moore, Ericdb9c9172006-03-14 09:14:18 -07001679 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001680 error = mpt_config(ioc, &cfg);
1681 if (error)
1682 goto out;
1683 if (!hdr.ExtPageLength) {
1684 error = -ENXIO;
1685 goto out;
1686 }
1687
1688 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1689 &dma_handle);
1690 if (!buffer) {
1691 error = -ENOMEM;
1692 goto out;
1693 }
1694
1695 cfg.physAddr = dma_handle;
1696 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1697
1698 error = mpt_config(ioc, &cfg);
1699 if (error)
1700 goto out_free_consistent;
1701
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301702 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001703
1704 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001705 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001706 device_info->handle_enclosure =
1707 le16_to_cpu(buffer->EnclosureHandle);
1708 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001709 device_info->phy_id = buffer->PhyNum;
1710 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001711 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001712 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001713 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001714 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1715 device_info->sas_address = le64_to_cpu(sas_address);
1716 device_info->device_info =
1717 le32_to_cpu(buffer->DeviceInfo);
1718
1719 out_free_consistent:
1720 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1721 buffer, dma_handle);
1722 out:
1723 return error;
1724}
1725
1726static int
1727mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1728 u32 form, u32 form_specific)
1729{
1730 ConfigExtendedPageHeader_t hdr;
1731 CONFIGPARMS cfg;
1732 SasExpanderPage0_t *buffer;
1733 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001734 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001735
1736 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1737 hdr.ExtPageLength = 0;
1738 hdr.PageNumber = 0;
1739 hdr.Reserved1 = 0;
1740 hdr.Reserved2 = 0;
1741 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1742 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1743
1744 cfg.cfghdr.ehdr = &hdr;
1745 cfg.physAddr = -1;
1746 cfg.pageAddr = form + form_specific;
1747 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1748 cfg.dir = 0; /* read */
1749 cfg.timeout = 10;
1750
Moore, Ericdb9c9172006-03-14 09:14:18 -07001751 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001752 error = mpt_config(ioc, &cfg);
1753 if (error)
1754 goto out;
1755
1756 if (!hdr.ExtPageLength) {
1757 error = -ENXIO;
1758 goto out;
1759 }
1760
1761 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1762 &dma_handle);
1763 if (!buffer) {
1764 error = -ENOMEM;
1765 goto out;
1766 }
1767
1768 cfg.physAddr = dma_handle;
1769 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1770
1771 error = mpt_config(ioc, &cfg);
1772 if (error)
1773 goto out_free_consistent;
1774
1775 /* save config data */
1776 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001777 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001778 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001779 if (!port_info->phy_info) {
1780 error = -ENOMEM;
1781 goto out_free_consistent;
1782 }
1783
Eric Moore2ecce492007-01-29 09:47:08 -07001784 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001785 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001786 port_info->phy_info[i].handle =
1787 le16_to_cpu(buffer->DevHandle);
1788 }
Eric Moore547f9a22006-06-27 14:42:12 -06001789
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001790 out_free_consistent:
1791 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1792 buffer, dma_handle);
1793 out:
1794 return error;
1795}
1796
1797static int
1798mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1799 u32 form, u32 form_specific)
1800{
1801 ConfigExtendedPageHeader_t hdr;
1802 CONFIGPARMS cfg;
1803 SasExpanderPage1_t *buffer;
1804 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001805 int error=0;
1806
1807 if (ioc->sas_discovery_runtime &&
1808 mptsas_is_end_device(&phy_info->attached))
1809 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001810
1811 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1812 hdr.ExtPageLength = 0;
1813 hdr.PageNumber = 1;
1814 hdr.Reserved1 = 0;
1815 hdr.Reserved2 = 0;
1816 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1817 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1818
1819 cfg.cfghdr.ehdr = &hdr;
1820 cfg.physAddr = -1;
1821 cfg.pageAddr = form + form_specific;
1822 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1823 cfg.dir = 0; /* read */
1824 cfg.timeout = 10;
1825
1826 error = mpt_config(ioc, &cfg);
1827 if (error)
1828 goto out;
1829
1830 if (!hdr.ExtPageLength) {
1831 error = -ENXIO;
1832 goto out;
1833 }
1834
1835 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1836 &dma_handle);
1837 if (!buffer) {
1838 error = -ENOMEM;
1839 goto out;
1840 }
1841
1842 cfg.physAddr = dma_handle;
1843 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1844
1845 error = mpt_config(ioc, &cfg);
1846 if (error)
1847 goto out_free_consistent;
1848
1849
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301850 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001851
1852 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001853 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854 phy_info->port_id = buffer->PhysicalPort;
1855 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1856 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1857 phy_info->hw_link_rate = buffer->HwLinkRate;
1858 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1859 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1860
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001861 out_free_consistent:
1862 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1863 buffer, dma_handle);
1864 out:
1865 return error;
1866}
1867
1868static void
1869mptsas_parse_device_info(struct sas_identify *identify,
1870 struct mptsas_devinfo *device_info)
1871{
1872 u16 protocols;
1873
1874 identify->sas_address = device_info->sas_address;
1875 identify->phy_identifier = device_info->phy_id;
1876
1877 /*
1878 * Fill in Phy Initiator Port Protocol.
1879 * Bits 6:3, more than one bit can be set, fall through cases.
1880 */
1881 protocols = device_info->device_info & 0x78;
1882 identify->initiator_port_protocols = 0;
1883 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1884 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1885 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1886 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1887 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1888 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1889 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1890 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1891
1892 /*
1893 * Fill in Phy Target Port Protocol.
1894 * Bits 10:7, more than one bit can be set, fall through cases.
1895 */
1896 protocols = device_info->device_info & 0x780;
1897 identify->target_port_protocols = 0;
1898 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1899 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1900 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1901 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1902 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1903 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1904 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1905 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1906
1907 /*
1908 * Fill in Attached device type.
1909 */
1910 switch (device_info->device_info &
1911 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1912 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1913 identify->device_type = SAS_PHY_UNUSED;
1914 break;
1915 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1916 identify->device_type = SAS_END_DEVICE;
1917 break;
1918 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1919 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1920 break;
1921 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1922 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1923 break;
1924 }
1925}
1926
1927static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001928 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001929{
Moore, Erice6b2d762006-03-14 09:14:24 -07001930 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001931 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001932 struct sas_port *port;
1933 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001934
Eric Moore547f9a22006-06-27 14:42:12 -06001935 if (!dev) {
1936 error = -ENODEV;
1937 goto out;
1938 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001939
1940 if (!phy_info->phy) {
1941 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001942 if (!phy) {
1943 error = -ENOMEM;
1944 goto out;
1945 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001946 } else
1947 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001948
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001949 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001950
1951 /*
1952 * Set Negotiated link rate.
1953 */
1954 switch (phy_info->negotiated_link_rate) {
1955 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001956 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001957 break;
1958 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001959 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001960 break;
1961 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001962 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001963 break;
1964 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001965 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001966 break;
1967 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1968 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1969 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001970 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001971 break;
1972 }
1973
1974 /*
1975 * Set Max hardware link rate.
1976 */
1977 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1978 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001979 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001980 break;
1981 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001982 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001983 break;
1984 default:
1985 break;
1986 }
1987
1988 /*
1989 * Set Max programmed link rate.
1990 */
1991 switch (phy_info->programmed_link_rate &
1992 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1993 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001994 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001995 break;
1996 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001997 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001998 break;
1999 default:
2000 break;
2001 }
2002
2003 /*
2004 * Set Min hardware link rate.
2005 */
2006 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2007 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002008 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002009 break;
2010 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002011 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002012 break;
2013 default:
2014 break;
2015 }
2016
2017 /*
2018 * Set Min programmed link rate.
2019 */
2020 switch (phy_info->programmed_link_rate &
2021 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2022 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002023 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002024 break;
2025 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002026 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002027 break;
2028 default:
2029 break;
2030 }
2031
Moore, Erice6b2d762006-03-14 09:14:24 -07002032 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002033
Moore, Erice6b2d762006-03-14 09:14:24 -07002034 error = sas_phy_add(phy);
2035 if (error) {
2036 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002037 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002038 }
2039 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002040 }
2041
Eric Moore547f9a22006-06-27 14:42:12 -06002042 if (!phy_info->attached.handle ||
2043 !phy_info->port_details)
2044 goto out;
2045
2046 port = mptsas_get_port(phy_info);
2047 ioc = phy_to_ioc(phy_info->phy);
2048
2049 if (phy_info->sas_port_add_phy) {
2050
2051 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002052 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002053 if (!port) {
2054 error = -ENOMEM;
2055 goto out;
2056 }
2057 error = sas_port_add(port);
2058 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302059 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002060 "%s: exit at line=%d\n", ioc->name,
2061 __FUNCTION__, __LINE__));
2062 goto out;
2063 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302064 mptsas_set_port(ioc, phy_info, port);
2065 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -06002066 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
2067 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002068 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302069 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
Eric Moore547f9a22006-06-27 14:42:12 -06002070 phy_info->phy_id));
2071 sas_port_add_phy(port, phy_info->phy);
2072 phy_info->sas_port_add_phy = 0;
2073 }
2074
2075 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002076
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002077 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002078 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002079 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002080
James Bottomley2686de22006-06-30 12:54:02 -05002081 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002082 /*
2083 * Let the hotplug_work thread handle processing
2084 * the adding/removing of devices that occur
2085 * after start of day.
2086 */
2087 if (ioc->sas_discovery_runtime &&
2088 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002089 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002090
James Bottomleyf013db32006-03-18 14:54:36 -06002091 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002092 if (scsi_is_host_device(parent)) {
2093 struct mptsas_portinfo *port_info;
2094 int i;
2095
2096 mutex_lock(&ioc->sas_topology_mutex);
2097 port_info = mptsas_find_portinfo_by_handle(ioc,
2098 ioc->handle);
2099 mutex_unlock(&ioc->sas_topology_mutex);
2100
2101 for (i = 0; i < port_info->num_phys; i++)
2102 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002103 identify.sas_address) {
2104 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002105 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002106 }
James Bottomley2686de22006-06-30 12:54:02 -05002107
2108 } else if (scsi_is_sas_rphy(parent)) {
2109 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2110 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002111 parent_rphy->identify.sas_address) {
2112 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002113 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002114 }
James Bottomley2686de22006-06-30 12:54:02 -05002115 }
2116
James Bottomleyf013db32006-03-18 14:54:36 -06002117 switch (identify.device_type) {
2118 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002119 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002120 break;
2121 case SAS_EDGE_EXPANDER_DEVICE:
2122 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002123 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002124 break;
2125 default:
2126 rphy = NULL;
2127 break;
2128 }
Eric Moore547f9a22006-06-27 14:42:12 -06002129 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302130 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002131 "%s: exit at line=%d\n", ioc->name,
2132 __FUNCTION__, __LINE__));
2133 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002134 }
2135
Eric Moore547f9a22006-06-27 14:42:12 -06002136 rphy->identify = identify;
2137 error = sas_rphy_add(rphy);
2138 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302139 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002140 "%s: exit at line=%d\n", ioc->name,
2141 __FUNCTION__, __LINE__));
2142 sas_rphy_free(rphy);
2143 goto out;
2144 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302145 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002146 }
2147
Eric Moore547f9a22006-06-27 14:42:12 -06002148 out:
2149 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002150}
2151
2152static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002153mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002154{
Moore, Erice6b2d762006-03-14 09:14:24 -07002155 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002156 int error = -ENOMEM, i;
2157
Moore, Erice6b2d762006-03-14 09:14:24 -07002158 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2159 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002160 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002161
Moore, Erice6b2d762006-03-14 09:14:24 -07002162 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002163 if (error)
2164 goto out_free_port_info;
2165
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302166 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002167 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002168 ioc->handle = hba->phy_info[0].handle;
2169 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002170 if (!port_info) {
2171 port_info = hba;
2172 list_add_tail(&port_info->list, &ioc->sas_topology);
2173 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002174 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002175 port_info->phy_info[i].negotiated_link_rate =
2176 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002177 port_info->phy_info[i].handle =
2178 hba->phy_info[i].handle;
2179 port_info->phy_info[i].port_id =
2180 hba->phy_info[i].port_id;
2181 }
Eric Moore547f9a22006-06-27 14:42:12 -06002182 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002183 kfree(hba);
2184 hba = NULL;
2185 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002186 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002187 for (i = 0; i < port_info->num_phys; i++) {
2188 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2189 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2190 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2191
2192 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002193 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2194 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2195 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002196 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002197 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002198 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002199 mptsas_sas_device_pg0(ioc,
2200 &port_info->phy_info[i].attached,
2201 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2202 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2203 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002204 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002205
Eric Moore547f9a22006-06-27 14:42:12 -06002206 mptsas_setup_wide_ports(ioc, port_info);
2207
2208 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002209 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002210 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002211
2212 return 0;
2213
2214 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002215 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002216 out:
2217 return error;
2218}
2219
2220static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002221mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002222{
Moore, Erice6b2d762006-03-14 09:14:24 -07002223 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002224 struct device *parent;
2225 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002226 int error = -ENOMEM, i, j;
2227
Moore, Erice6b2d762006-03-14 09:14:24 -07002228 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2229 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002230 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002231
Moore, Erice6b2d762006-03-14 09:14:24 -07002232 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002233 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2234 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002235 if (error)
2236 goto out_free_port_info;
2237
Eric Moore2ecce492007-01-29 09:47:08 -07002238 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002239
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002240 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002241 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2242 if (!port_info) {
2243 port_info = ex;
2244 list_add_tail(&port_info->list, &ioc->sas_topology);
2245 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002246 for (i = 0; i < ex->num_phys; i++) {
2247 port_info->phy_info[i].handle =
2248 ex->phy_info[i].handle;
2249 port_info->phy_info[i].port_id =
2250 ex->phy_info[i].port_id;
2251 }
Eric Moore547f9a22006-06-27 14:42:12 -06002252 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002253 kfree(ex);
2254 ex = NULL;
2255 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002256 mutex_unlock(&ioc->sas_topology_mutex);
2257
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002258 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002259 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2260 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2261 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2262
2263 if (port_info->phy_info[i].identify.handle) {
2264 mptsas_sas_device_pg0(ioc,
2265 &port_info->phy_info[i].identify,
2266 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2267 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2268 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002269 port_info->phy_info[i].identify.phy_id =
2270 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002271 }
2272
2273 if (port_info->phy_info[i].attached.handle) {
2274 mptsas_sas_device_pg0(ioc,
2275 &port_info->phy_info[i].attached,
2276 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2277 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2278 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002279 port_info->phy_info[i].attached.phy_id =
2280 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002281 }
Eric Moore547f9a22006-06-27 14:42:12 -06002282 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283
Eric Moore547f9a22006-06-27 14:42:12 -06002284 parent = &ioc->sh->shost_gendev;
2285 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002286 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002287 list_for_each_entry(p, &ioc->sas_topology, list) {
2288 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002289 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002290 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002291 continue;
2292 rphy = mptsas_get_rphy(&p->phy_info[j]);
2293 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002294 }
2295 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002296 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002297 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002298
Eric Moore547f9a22006-06-27 14:42:12 -06002299 mptsas_setup_wide_ports(ioc, port_info);
2300
2301 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002302 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002303 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002304
2305 return 0;
2306
2307 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002308 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002309 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002310 kfree(ex);
2311 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002312 out:
2313 return error;
2314}
2315
Moore, Erice6b2d762006-03-14 09:14:24 -07002316/*
2317 * mptsas_delete_expander_phys
2318 *
2319 *
2320 * This will traverse topology, and remove expanders
2321 * that are no longer present
2322 */
2323static void
2324mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2325{
2326 struct mptsas_portinfo buffer;
2327 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002328 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002329 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002330 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002331 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002332
2333 mutex_lock(&ioc->sas_topology_mutex);
2334 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2335
2336 if (port_info->phy_info &&
2337 (!(port_info->phy_info[0].identify.device_info &
2338 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2339 continue;
2340
2341 if (mptsas_sas_expander_pg0(ioc, &buffer,
2342 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002343 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2344 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002345
2346 /*
2347 * Obtain the port_info instance to the parent port
2348 */
2349 parent = mptsas_find_portinfo_by_handle(ioc,
2350 port_info->phy_info[0].identify.handle_parent);
2351
2352 if (!parent)
2353 goto next_port;
2354
Eric Moore547f9a22006-06-27 14:42:12 -06002355 expander_sas_address =
2356 port_info->phy_info[0].identify.sas_address;
2357
Moore, Erice6b2d762006-03-14 09:14:24 -07002358 /*
2359 * Delete rphys in the parent that point
2360 * to this expander. The transport layer will
2361 * cleanup all the children.
2362 */
Eric Moore547f9a22006-06-27 14:42:12 -06002363 phy_info = parent->phy_info;
2364 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2365 port = mptsas_get_port(phy_info);
2366 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002367 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002368 if (phy_info->attached.sas_address !=
2369 expander_sas_address)
2370 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302371 dsaswideprintk(ioc,
2372 dev_printk(KERN_DEBUG, &port->dev,
2373 "delete port (%d)\n", port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002374 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302375 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002376 }
2377 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002378
2379 phy_info = port_info->phy_info;
2380 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302381 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002382
Moore, Erice6b2d762006-03-14 09:14:24 -07002383 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002384 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002385 kfree(port_info);
2386 }
2387 /*
2388 * Free this memory allocated from inside
2389 * mptsas_sas_expander_pg0
2390 */
Eric Moore547f9a22006-06-27 14:42:12 -06002391 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002392 }
2393 mutex_unlock(&ioc->sas_topology_mutex);
2394}
2395
2396/*
2397 * Start of day discovery
2398 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002399static void
2400mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2401{
2402 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002403 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002404
Moore, Erice6b2d762006-03-14 09:14:24 -07002405 mutex_lock(&ioc->sas_discovery_mutex);
2406 mptsas_probe_hba_phys(ioc);
2407 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002408 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002409 /*
2410 Reporting RAID volumes.
2411 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002412 if (!ioc->ir_firmware)
2413 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002414 if (!ioc->raid_data.pIocPg2)
2415 goto out;
2416 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2417 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002418 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002419 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002420 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2421 }
2422 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002423 mutex_unlock(&ioc->sas_discovery_mutex);
2424}
2425
2426/*
2427 * Work queue thread to handle Runtime discovery
2428 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002429 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002430 */
2431static void
Eric Moore547f9a22006-06-27 14:42:12 -06002432__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002433{
Moore, Erice6b2d762006-03-14 09:14:24 -07002434 u32 handle = 0xFFFF;
2435
Moore, Erice6b2d762006-03-14 09:14:24 -07002436 ioc->sas_discovery_runtime=1;
2437 mptsas_delete_expander_phys(ioc);
2438 mptsas_probe_hba_phys(ioc);
2439 while (!mptsas_probe_expander_phys(ioc, &handle))
2440 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002441 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002442}
2443
2444/*
2445 * Work queue thread to handle Runtime discovery
2446 * Mere purpose is the hot add/delete of expanders
2447 *(Mutex LOCKED)
2448 */
2449static void
David Howellsc4028952006-11-22 14:57:56 +00002450mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002451{
David Howellsc4028952006-11-22 14:57:56 +00002452 struct mptsas_discovery_event *ev =
2453 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002454 MPT_ADAPTER *ioc = ev->ioc;
2455
2456 mutex_lock(&ioc->sas_discovery_mutex);
2457 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002458 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002459 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002460}
2461
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002462static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002463mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002464{
2465 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002466 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002467 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002468
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002469 mutex_lock(&ioc->sas_topology_mutex);
2470 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2471 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002472 if (!mptsas_is_end_device(
2473 &port_info->phy_info[i].attached))
2474 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002475 if (port_info->phy_info[i].attached.sas_address
2476 != sas_address)
2477 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002478 phy_info = &port_info->phy_info[i];
2479 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002480 }
2481 }
2482 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002483 return phy_info;
2484}
2485
2486static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002487mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002488{
2489 struct mptsas_portinfo *port_info;
2490 struct mptsas_phyinfo *phy_info = NULL;
2491 int i;
2492
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002493 mutex_lock(&ioc->sas_topology_mutex);
2494 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002495 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002496 if (!mptsas_is_end_device(
2497 &port_info->phy_info[i].attached))
2498 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002499 if (port_info->phy_info[i].attached.id != id)
2500 continue;
2501 if (port_info->phy_info[i].attached.channel != channel)
2502 continue;
2503 phy_info = &port_info->phy_info[i];
2504 break;
2505 }
2506 }
2507 mutex_unlock(&ioc->sas_topology_mutex);
2508 return phy_info;
2509}
2510
2511static struct mptsas_phyinfo *
2512mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2513{
2514 struct mptsas_portinfo *port_info;
2515 struct mptsas_phyinfo *phy_info = NULL;
2516 int i;
2517
2518 mutex_lock(&ioc->sas_topology_mutex);
2519 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2520 for (i = 0; i < port_info->num_phys; i++) {
2521 if (!mptsas_is_end_device(
2522 &port_info->phy_info[i].attached))
2523 continue;
2524 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2525 continue;
2526 if (port_info->phy_info[i].attached.phys_disk_num != id)
2527 continue;
2528 if (port_info->phy_info[i].attached.channel != channel)
2529 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002530 phy_info = &port_info->phy_info[i];
2531 break;
2532 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002533 }
2534 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002535 return phy_info;
2536}
2537
Moore, Eric4b766472006-03-14 09:14:12 -07002538/*
2539 * Work queue thread to clear the persitency table
2540 */
2541static void
David Howellsc4028952006-11-22 14:57:56 +00002542mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002543{
David Howellsc4028952006-11-22 14:57:56 +00002544 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002545
2546 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2547}
2548
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002549static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002550mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2551{
Eric Mooref99be432007-01-04 20:46:54 -07002552 int rc;
2553
Moore, Ericf44e5462006-03-14 09:14:21 -07002554 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002555 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002556}
2557
2558static void
2559mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2560{
2561 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2562 mptsas_reprobe_lun);
2563}
2564
Eric Mooreb506ade2007-01-29 09:45:37 -07002565static void
2566mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2567{
2568 CONFIGPARMS cfg;
2569 ConfigPageHeader_t hdr;
2570 dma_addr_t dma_handle;
2571 pRaidVolumePage0_t buffer = NULL;
2572 RaidPhysDiskPage0_t phys_disk;
2573 int i;
2574 struct mptsas_hotplug_event *ev;
2575
2576 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2577 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2578 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2579 cfg.pageAddr = (channel << 8) + id;
2580 cfg.cfghdr.hdr = &hdr;
2581 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2582
2583 if (mpt_config(ioc, &cfg) != 0)
2584 goto out;
2585
2586 if (!hdr.PageLength)
2587 goto out;
2588
2589 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2590 &dma_handle);
2591
2592 if (!buffer)
2593 goto out;
2594
2595 cfg.physAddr = dma_handle;
2596 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2597
2598 if (mpt_config(ioc, &cfg) != 0)
2599 goto out;
2600
2601 if (!(buffer->VolumeStatus.Flags &
2602 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2603 goto out;
2604
2605 if (!buffer->NumPhysDisks)
2606 goto out;
2607
2608 for (i = 0; i < buffer->NumPhysDisks; i++) {
2609
2610 if (mpt_raid_phys_disk_pg0(ioc,
2611 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2612 continue;
2613
2614 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2615 if (!ev) {
2616 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2617 goto out;
2618 }
2619
2620 INIT_WORK(&ev->work, mptsas_hotplug_work);
2621 ev->ioc = ioc;
2622 ev->id = phys_disk.PhysDiskID;
2623 ev->channel = phys_disk.PhysDiskBus;
2624 ev->phys_disk_num_valid = 1;
2625 ev->phys_disk_num = phys_disk.PhysDiskNum;
2626 ev->event_type = MPTSAS_ADD_DEVICE;
2627 schedule_work(&ev->work);
2628 }
2629
2630 out:
2631 if (buffer)
2632 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2633 dma_handle);
2634}
Moore, Erice6b2d762006-03-14 09:14:24 -07002635/*
2636 * Work queue thread to handle SAS hotplug events
2637 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002638static void
David Howellsc4028952006-11-22 14:57:56 +00002639mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002640{
David Howellsc4028952006-11-22 14:57:56 +00002641 struct mptsas_hotplug_event *ev =
2642 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002643
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002644 MPT_ADAPTER *ioc = ev->ioc;
2645 struct mptsas_phyinfo *phy_info;
2646 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002647 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002648 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002649 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002650 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002651 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002652 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002653 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002654 VirtDevice *vdevice;
2655
Moore, Erice6b2d762006-03-14 09:14:24 -07002656 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002657 switch (ev->event_type) {
2658 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002659
Eric Mooreb506ade2007-01-29 09:45:37 -07002660 phy_info = NULL;
2661 if (ev->phys_disk_num_valid) {
2662 if (ev->hidden_raid_component){
2663 if (mptsas_sas_device_pg0(ioc, &sas_device,
2664 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2665 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2666 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302667 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002668 "%s: exit at line=%d\n", ioc->name,
2669 __FUNCTION__, __LINE__));
2670 break;
2671 }
2672 phy_info = mptsas_find_phyinfo_by_sas_address(
2673 ioc, sas_device.sas_address);
2674 }else
2675 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2676 ioc, ev->channel, ev->phys_disk_num);
2677 }
2678
2679 if (!phy_info)
2680 phy_info = mptsas_find_phyinfo_by_target(ioc,
2681 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002682
Moore, Ericf44e5462006-03-14 09:14:21 -07002683 /*
2684 * Sanity checks, for non-existing phys and remote rphys.
2685 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002686 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302687 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002688 "%s: exit at line=%d\n", ioc->name,
2689 __FUNCTION__, __LINE__));
2690 break;
2691 }
2692 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302693 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002694 "%s: exit at line=%d\n", ioc->name,
2695 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002696 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002697 }
2698 rphy = mptsas_get_rphy(phy_info);
2699 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302700 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002701 "%s: exit at line=%d\n", ioc->name,
2702 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002703 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002704 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002705
Eric Moore547f9a22006-06-27 14:42:12 -06002706 port = mptsas_get_port(phy_info);
2707 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302708 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002709 "%s: exit at line=%d\n", ioc->name,
2710 __FUNCTION__, __LINE__));
2711 break;
2712 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002713
Eric Moore547f9a22006-06-27 14:42:12 -06002714 starget = mptsas_get_starget(phy_info);
2715 if (starget) {
2716 vtarget = starget->hostdata;
2717
2718 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302719 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002720 "%s: exit at line=%d\n", ioc->name,
2721 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002722 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002723 }
2724
Moore, Ericf44e5462006-03-14 09:14:21 -07002725 /*
2726 * Handling RAID components
2727 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002728 if (ev->phys_disk_num_valid &&
2729 ev->hidden_raid_component) {
2730 printk(MYIOC_s_INFO_FMT
2731 "RAID Hidding: channel=%d, id=%d, "
2732 "physdsk %d \n", ioc->name, ev->channel,
2733 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002734 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002735 vtarget->tflags |=
2736 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002737 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002738 phy_info->attached.phys_disk_num =
2739 ev->phys_disk_num;
2740 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002741 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002742 }
2743
Eric Mooreb506ade2007-01-29 09:45:37 -07002744 if (phy_info->attached.device_info &
2745 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002746 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002747 if (phy_info->attached.device_info &
2748 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002749 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002750 if (phy_info->attached.device_info &
2751 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002752 ds = "sata";
2753
2754 printk(MYIOC_s_INFO_FMT
2755 "removing %s device, channel %d, id %d, phy %d\n",
2756 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Mooredc22f162006-07-06 11:23:14 -06002757 dev_printk(KERN_DEBUG, &port->dev,
2758 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002759 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302760 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002761 break;
2762 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002763
Moore, Ericbd23e942006-04-17 12:43:04 -06002764 if (ev->phys_disk_num_valid)
2765 mpt_findImVolumes(ioc);
2766
Moore, Ericc73787ee2006-01-26 16:20:06 -07002767 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002768 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002769 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002770 if (mptsas_sas_device_pg0(ioc, &sas_device,
2771 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002772 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2773 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302774 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002775 "%s: exit at line=%d\n", ioc->name,
2776 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002777 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002778 }
2779
Eric Moore547f9a22006-06-27 14:42:12 -06002780 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002781
Eric Moore547f9a22006-06-27 14:42:12 -06002782 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2783 sas_device.sas_address);
2784
2785 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302786 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002787 "%s: exit at line=%d\n", ioc->name,
2788 __FUNCTION__, __LINE__));
2789 break;
2790 }
2791
2792 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002793 if (starget && (!ev->hidden_raid_component)){
2794
Eric Moore547f9a22006-06-27 14:42:12 -06002795 vtarget = starget->hostdata;
2796
2797 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302798 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002799 "%s: exit at line=%d\n", ioc->name,
2800 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002801 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002802 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002803 /*
2804 * Handling RAID components
2805 */
2806 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002807 printk(MYIOC_s_INFO_FMT
2808 "RAID Exposing: channel=%d, id=%d, "
2809 "physdsk %d \n", ioc->name, ev->channel,
2810 ev->id, ev->phys_disk_num);
2811 vtarget->tflags &=
2812 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002813 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002814 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002815 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002816 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002817 break;
2818 }
2819
Eric Moore547f9a22006-06-27 14:42:12 -06002820 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302821 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002822 "%s: exit at line=%d\n", ioc->name,
2823 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002824 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002825 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002826 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002827
Eric Moore547f9a22006-06-27 14:42:12 -06002828 port = mptsas_get_port(phy_info);
2829 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302830 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002831 "%s: exit at line=%d\n", ioc->name,
2832 __FUNCTION__, __LINE__));
2833 break;
2834 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002835 memcpy(&phy_info->attached, &sas_device,
2836 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002837
Eric Mooreb506ade2007-01-29 09:45:37 -07002838 if (phy_info->attached.device_info &
2839 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002840 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002841 if (phy_info->attached.device_info &
2842 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002843 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002844 if (phy_info->attached.device_info &
2845 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002846 ds = "sata";
2847
2848 printk(MYIOC_s_INFO_FMT
2849 "attaching %s device, channel %d, id %d, phy %d\n",
2850 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2851
James Bottomleyf013db32006-03-18 14:54:36 -06002852 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002853 rphy = sas_end_device_alloc(port);
2854 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302855 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002856 "%s: exit at line=%d\n", ioc->name,
2857 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002858 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002859 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002860
James Bottomleyf013db32006-03-18 14:54:36 -06002861 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002862 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302863 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002864 "%s: exit at line=%d\n", ioc->name,
2865 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002866 sas_rphy_free(rphy);
2867 break;
2868 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302869 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002870 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002871 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002872 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2873 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002874 if (sdev) {
2875 scsi_device_put(sdev);
2876 break;
2877 }
2878 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002879 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002880 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2881 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002882 mpt_findImVolumes(ioc);
2883 break;
2884 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002885 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002886 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002887 if (!sdev)
2888 break;
2889 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002890 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002891 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002892 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002893 scsi_remove_device(sdev);
2894 scsi_device_put(sdev);
2895 mpt_findImVolumes(ioc);
2896 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002897 case MPTSAS_ADD_INACTIVE_VOLUME:
2898 mptsas_adding_inactive_raid_components(ioc,
2899 ev->channel, ev->id);
2900 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002901 case MPTSAS_IGNORE_EVENT:
2902 default:
2903 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002904 }
2905
Moore, Erice6b2d762006-03-14 09:14:24 -07002906 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002907 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002908}
2909
2910static void
Eric Moore547f9a22006-06-27 14:42:12 -06002911mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002912 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2913{
2914 struct mptsas_hotplug_event *ev;
2915 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2916 __le64 sas_address;
2917
2918 if ((device_info &
2919 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2920 MPI_SAS_DEVICE_INFO_STP_TARGET |
2921 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2922 return;
2923
Moore, Eric4b766472006-03-14 09:14:12 -07002924 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002925 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002926
2927 mptsas_target_reset_queue(ioc, sas_event_data);
2928 break;
2929
2930 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002931 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002932 if (!ev) {
2933 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2934 break;
2935 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002936
David Howellsc4028952006-11-22 14:57:56 +00002937 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002938 ev->ioc = ioc;
2939 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2940 ev->parent_handle =
2941 le16_to_cpu(sas_event_data->ParentDevHandle);
2942 ev->channel = sas_event_data->Bus;
2943 ev->id = sas_event_data->TargetID;
2944 ev->phy_id = sas_event_data->PhyNum;
2945 memcpy(&sas_address, &sas_event_data->SASAddress,
2946 sizeof(__le64));
2947 ev->sas_address = le64_to_cpu(sas_address);
2948 ev->device_info = device_info;
2949
2950 if (sas_event_data->ReasonCode &
2951 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2952 ev->event_type = MPTSAS_ADD_DEVICE;
2953 else
2954 ev->event_type = MPTSAS_DEL_DEVICE;
2955 schedule_work(&ev->work);
2956 break;
2957 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2958 /*
2959 * Persistent table is full.
2960 */
Eric Moore547f9a22006-06-27 14:42:12 -06002961 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002962 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002963 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002964 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002965 /*
2966 * TODO, handle other events
2967 */
Moore, Eric4b766472006-03-14 09:14:12 -07002968 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002969 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002970 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002971 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2972 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2973 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2974 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002975 default:
2976 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002977 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002978}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002979static void
Eric Moore547f9a22006-06-27 14:42:12 -06002980mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002981 EVENT_DATA_RAID *raid_event_data)
2982{
2983 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002984 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2985 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002986
2987 if (ioc->bus_type != SAS)
2988 return;
2989
Eric Moore547f9a22006-06-27 14:42:12 -06002990 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002991 if (!ev) {
2992 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2993 return;
2994 }
2995
David Howellsc4028952006-11-22 14:57:56 +00002996 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002997 ev->ioc = ioc;
2998 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002999 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06003000 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003001
3002 switch (raid_event_data->ReasonCode) {
3003 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07003004 ev->phys_disk_num_valid = 1;
3005 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003006 ev->event_type = MPTSAS_ADD_DEVICE;
3007 break;
3008 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07003009 ev->phys_disk_num_valid = 1;
3010 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003011 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003012 ev->event_type = MPTSAS_DEL_DEVICE;
3013 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003014 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3015 switch (state) {
3016 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003017 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06003018 ev->phys_disk_num_valid = 1;
3019 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003020 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06003021 ev->event_type = MPTSAS_ADD_DEVICE;
3022 break;
3023 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003024 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3025 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3026 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07003027 ev->phys_disk_num_valid = 1;
3028 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06003029 ev->event_type = MPTSAS_DEL_DEVICE;
3030 break;
3031 default:
3032 break;
3033 }
3034 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003035 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
3036 ev->event_type = MPTSAS_DEL_RAID;
3037 break;
3038 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
3039 ev->event_type = MPTSAS_ADD_RAID;
3040 break;
3041 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003042 switch (state) {
3043 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3044 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
3045 ev->event_type = MPTSAS_DEL_RAID;
3046 break;
3047 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3048 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
3049 ev->event_type = MPTSAS_ADD_RAID;
3050 break;
3051 default:
3052 break;
3053 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003054 break;
3055 default:
3056 break;
3057 }
3058 schedule_work(&ev->work);
3059}
3060
Moore, Erice6b2d762006-03-14 09:14:24 -07003061static void
Eric Moore547f9a22006-06-27 14:42:12 -06003062mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003063 EVENT_DATA_SAS_DISCOVERY *discovery_data)
3064{
3065 struct mptsas_discovery_event *ev;
3066
3067 /*
3068 * DiscoveryStatus
3069 *
3070 * This flag will be non-zero when firmware
3071 * kicks off discovery, and return to zero
3072 * once its completed.
3073 */
3074 if (discovery_data->DiscoveryStatus)
3075 return;
3076
Eric Moore547f9a22006-06-27 14:42:12 -06003077 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003078 if (!ev)
3079 return;
David Howellsc4028952006-11-22 14:57:56 +00003080 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003081 ev->ioc = ioc;
3082 schedule_work(&ev->work);
3083};
3084
Eric Mooreb506ade2007-01-29 09:45:37 -07003085/*
3086 * mptsas_send_ir2_event - handle exposing hidden disk when
3087 * an inactive raid volume is added
3088 *
3089 * @ioc: Pointer to MPT_ADAPTER structure
3090 * @ir2_data
3091 *
3092 */
3093static void
3094mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3095{
3096 struct mptsas_hotplug_event *ev;
3097
3098 if (ir2_data->ReasonCode !=
3099 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3100 return;
3101
3102 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3103 if (!ev)
3104 return;
3105
3106 INIT_WORK(&ev->work, mptsas_hotplug_work);
3107 ev->ioc = ioc;
3108 ev->id = ir2_data->TargetID;
3109 ev->channel = ir2_data->Bus;
3110 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3111
3112 schedule_work(&ev->work);
3113};
Moore, Erice6b2d762006-03-14 09:14:24 -07003114
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003115static int
3116mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3117{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003118 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003119 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3120
3121 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003122 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003123
Moore, Erice6b2d762006-03-14 09:14:24 -07003124 /*
3125 * sas_discovery_ignore_events
3126 *
3127 * This flag is to prevent anymore processing of
3128 * sas events once mptsas_remove function is called.
3129 */
3130 if (ioc->sas_discovery_ignore_events) {
3131 rc = mptscsih_event_process(ioc, reply);
3132 goto out;
3133 }
3134
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003135 switch (event) {
3136 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003137 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003138 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003139 break;
3140 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003141 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003142 (EVENT_DATA_RAID *)reply->Data);
3143 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003144 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003145 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003146 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003147 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003148 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003149 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003150 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003151 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3152 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003153 case MPI_EVENT_IR2:
3154 mptsas_send_ir2_event(ioc,
3155 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3156 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003157 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003158 rc = mptscsih_event_process(ioc, reply);
3159 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003160 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003161 out:
3162
3163 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003164}
3165
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003166static int
3167mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3168{
3169 struct Scsi_Host *sh;
3170 MPT_SCSI_HOST *hd;
3171 MPT_ADAPTER *ioc;
3172 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003173 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003174 int numSGE = 0;
3175 int scale;
3176 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003177 int error=0;
3178 int r;
3179
3180 r = mpt_attach(pdev,id);
3181 if (r)
3182 return r;
3183
3184 ioc = pci_get_drvdata(pdev);
3185 ioc->DoneCtx = mptsasDoneCtx;
3186 ioc->TaskCtx = mptsasTaskCtx;
3187 ioc->InternalCtx = mptsasInternalCtx;
3188
3189 /* Added sanity check on readiness of the MPT adapter.
3190 */
3191 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3192 printk(MYIOC_s_WARN_FMT
3193 "Skipping because it's not operational!\n",
3194 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003195 error = -ENODEV;
3196 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003197 }
3198
3199 if (!ioc->active) {
3200 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3201 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003202 error = -ENODEV;
3203 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003204 }
3205
3206 /* Sanity check - ensure at least 1 port is INITIATOR capable
3207 */
3208 ioc_cap = 0;
3209 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3210 if (ioc->pfacts[ii].ProtocolFlags &
3211 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3212 ioc_cap++;
3213 }
3214
3215 if (!ioc_cap) {
3216 printk(MYIOC_s_WARN_FMT
3217 "Skipping ioc=%p because SCSI Initiator mode "
3218 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003219 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003220 }
3221
3222 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3223 if (!sh) {
3224 printk(MYIOC_s_WARN_FMT
3225 "Unable to register controller with SCSI subsystem\n",
3226 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003227 error = -1;
3228 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003229 }
3230
3231 spin_lock_irqsave(&ioc->FreeQlock, flags);
3232
3233 /* Attach the SCSI Host to the IOC structure
3234 */
3235 ioc->sh = sh;
3236
3237 sh->io_port = 0;
3238 sh->n_io_port = 0;
3239 sh->irq = 0;
3240
3241 /* set 16 byte cdb's */
3242 sh->max_cmd_len = 16;
3243
Eric Moore793955f2007-01-29 09:42:20 -07003244 sh->max_id = ioc->pfacts[0].PortSCSIID;
3245 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003246
3247 sh->transportt = mptsas_transport_template;
3248
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249 sh->this_id = ioc->pfacts[0].PortSCSIID;
3250
3251 /* Required entry.
3252 */
3253 sh->unique_id = ioc->id;
3254
3255 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003256 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003257 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003258 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003259 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003260
3261 /* Verify that we won't exceed the maximum
3262 * number of chain buffers
3263 * We can optimize: ZZ = req_sz/sizeof(SGE)
3264 * For 32bit SGE's:
3265 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3266 * + (req_sz - 64)/sizeof(SGE)
3267 * A slightly different algorithm is required for
3268 * 64bit SGEs.
3269 */
3270 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3271 if (sizeof(dma_addr_t) == sizeof(u64)) {
3272 numSGE = (scale - 1) *
3273 (ioc->facts.MaxChainDepth-1) + scale +
3274 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3275 sizeof(u32));
3276 } else {
3277 numSGE = 1 + (scale - 1) *
3278 (ioc->facts.MaxChainDepth-1) + scale +
3279 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3280 sizeof(u32));
3281 }
3282
3283 if (numSGE < sh->sg_tablesize) {
3284 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303285 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003286 "Resetting sg_tablesize to %d from %d\n",
3287 ioc->name, numSGE, sh->sg_tablesize));
3288 sh->sg_tablesize = numSGE;
3289 }
3290
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003291 hd = (MPT_SCSI_HOST *) sh->hostdata;
3292 hd->ioc = ioc;
3293
3294 /* SCSI needs scsi_cmnd lookup table!
3295 * (with size equal to req_depth*PtrSz!)
3296 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003297 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3298 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003299 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003300 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003301 }
3302
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303303 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003304 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003305
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003306 /* Clear the TM flags
3307 */
3308 hd->tmPending = 0;
3309 hd->tmState = TM_STATE_NONE;
3310 hd->resetPending = 0;
3311 hd->abortSCpnt = NULL;
3312
3313 /* Clear the pointer used to store
3314 * single-threaded commands, i.e., those
3315 * issued during a bus scan, dv and
3316 * configuration pages.
3317 */
3318 hd->cmdPtr = NULL;
3319
3320 /* Initialize this SCSI Hosts' timers
3321 * To use, set the timer expires field
3322 * and add_timer
3323 */
3324 init_timer(&hd->timer);
3325 hd->timer.data = (unsigned long) hd;
3326 hd->timer.function = mptscsih_timer_expired;
3327
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003328 ioc->sas_data.ptClear = mpt_pt_clear;
3329
Eric Mooredf9e0622007-01-29 09:46:21 -07003330 init_waitqueue_head(&hd->scandv_waitq);
3331 hd->scandv_wait_done = 0;
3332 hd->last_queue_full = 0;
3333 INIT_LIST_HEAD(&hd->target_reset_list);
3334 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3335
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003336 if (ioc->sas_data.ptClear==1) {
3337 mptbase_sas_persist_operation(
3338 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3339 }
3340
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003341 error = scsi_add_host(sh, &ioc->pcidev->dev);
3342 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303343 dprintk(ioc, printk(KERN_ERR MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003344 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003345 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003346 }
3347
3348 mptsas_scan_sas_topology(ioc);
3349
3350 return 0;
3351
Eric Moore547f9a22006-06-27 14:42:12 -06003352 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003353
3354 mptscsih_remove(pdev);
3355 return error;
3356}
3357
3358static void __devexit mptsas_remove(struct pci_dev *pdev)
3359{
3360 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3361 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003362 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003363
Eric Mooreb506ade2007-01-29 09:45:37 -07003364 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003365 sas_remove_host(ioc->sh);
3366
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003367 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003368 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3369 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003370 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303371 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003372 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003373 kfree(p);
3374 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003375 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003376
3377 mptscsih_remove(pdev);
3378}
3379
3380static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003381 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
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_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003384 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003385 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003386 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003387 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003388 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003389 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003390 PCI_ANY_ID, PCI_ANY_ID },
3391 {0} /* Terminating entry */
3392};
3393MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3394
3395
3396static struct pci_driver mptsas_driver = {
3397 .name = "mptsas",
3398 .id_table = mptsas_pci_table,
3399 .probe = mptsas_probe,
3400 .remove = __devexit_p(mptsas_remove),
3401 .shutdown = mptscsih_shutdown,
3402#ifdef CONFIG_PM
3403 .suspend = mptscsih_suspend,
3404 .resume = mptscsih_resume,
3405#endif
3406};
3407
3408static int __init
3409mptsas_init(void)
3410{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303411 int error;
3412
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003413 show_mptmod_ver(my_NAME, my_VERSION);
3414
3415 mptsas_transport_template =
3416 sas_attach_transport(&mptsas_transport_functions);
3417 if (!mptsas_transport_template)
3418 return -ENODEV;
3419
3420 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003421 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003422 mptsasInternalCtx =
3423 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003424 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003425
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303426 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3427 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003428
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303429 error = pci_register_driver(&mptsas_driver);
3430 if (error)
3431 sas_release_transport(mptsas_transport_template);
3432
3433 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003434}
3435
3436static void __exit
3437mptsas_exit(void)
3438{
3439 pci_unregister_driver(&mptsas_driver);
3440 sas_release_transport(mptsas_transport_template);
3441
3442 mpt_reset_deregister(mptsasDoneCtx);
3443 mpt_event_deregister(mptsasDoneCtx);
3444
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003445 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003446 mpt_deregister(mptsasInternalCtx);
3447 mpt_deregister(mptsasTaskCtx);
3448 mpt_deregister(mptsasDoneCtx);
3449}
3450
3451module_init(mptsas_init);
3452module_exit(mptsas_exit);