blob: 29add83da58863e8854af63d4fbe2ed3c78f14ec [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
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001315static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001316 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001317 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1318 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001319 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001320};
1321
1322static struct scsi_transport_template *mptsas_transport_template;
1323
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001324static int
1325mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1326{
1327 ConfigExtendedPageHeader_t hdr;
1328 CONFIGPARMS cfg;
1329 SasIOUnitPage0_t *buffer;
1330 dma_addr_t dma_handle;
1331 int error, i;
1332
1333 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1334 hdr.ExtPageLength = 0;
1335 hdr.PageNumber = 0;
1336 hdr.Reserved1 = 0;
1337 hdr.Reserved2 = 0;
1338 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1339 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1340
1341 cfg.cfghdr.ehdr = &hdr;
1342 cfg.physAddr = -1;
1343 cfg.pageAddr = 0;
1344 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1345 cfg.dir = 0; /* read */
1346 cfg.timeout = 10;
1347
1348 error = mpt_config(ioc, &cfg);
1349 if (error)
1350 goto out;
1351 if (!hdr.ExtPageLength) {
1352 error = -ENXIO;
1353 goto out;
1354 }
1355
1356 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1357 &dma_handle);
1358 if (!buffer) {
1359 error = -ENOMEM;
1360 goto out;
1361 }
1362
1363 cfg.physAddr = dma_handle;
1364 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1365
1366 error = mpt_config(ioc, &cfg);
1367 if (error)
1368 goto out_free_consistent;
1369
1370 port_info->num_phys = buffer->NumPhys;
1371 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001372 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001373 if (!port_info->phy_info) {
1374 error = -ENOMEM;
1375 goto out_free_consistent;
1376 }
1377
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301378 ioc->nvdata_version_persistent =
1379 le16_to_cpu(buffer->NvdataVersionPersistent);
1380 ioc->nvdata_version_default =
1381 le16_to_cpu(buffer->NvdataVersionDefault);
1382
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001383 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301384 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001385 port_info->phy_info[i].phy_id = i;
1386 port_info->phy_info[i].port_id =
1387 buffer->PhyData[i].Port;
1388 port_info->phy_info[i].negotiated_link_rate =
1389 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001390 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001391 port_info->phy_info[i].handle =
1392 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001393 }
1394
1395 out_free_consistent:
1396 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1397 buffer, dma_handle);
1398 out:
1399 return error;
1400}
1401
1402static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301403mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1404{
1405 ConfigExtendedPageHeader_t hdr;
1406 CONFIGPARMS cfg;
1407 SasIOUnitPage1_t *buffer;
1408 dma_addr_t dma_handle;
1409 int error;
1410 u16 device_missing_delay;
1411
1412 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1413 memset(&cfg, 0, sizeof(CONFIGPARMS));
1414
1415 cfg.cfghdr.ehdr = &hdr;
1416 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1417 cfg.timeout = 10;
1418 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1419 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1420 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1421 cfg.cfghdr.ehdr->PageNumber = 1;
1422
1423 error = mpt_config(ioc, &cfg);
1424 if (error)
1425 goto out;
1426 if (!hdr.ExtPageLength) {
1427 error = -ENXIO;
1428 goto out;
1429 }
1430
1431 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1432 &dma_handle);
1433 if (!buffer) {
1434 error = -ENOMEM;
1435 goto out;
1436 }
1437
1438 cfg.physAddr = dma_handle;
1439 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1440
1441 error = mpt_config(ioc, &cfg);
1442 if (error)
1443 goto out_free_consistent;
1444
1445 ioc->io_missing_delay =
1446 le16_to_cpu(buffer->IODeviceMissingDelay);
1447 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1448 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1449 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1450 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1451
1452 out_free_consistent:
1453 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1454 buffer, dma_handle);
1455 out:
1456 return error;
1457}
1458
1459static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001460mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1461 u32 form, u32 form_specific)
1462{
1463 ConfigExtendedPageHeader_t hdr;
1464 CONFIGPARMS cfg;
1465 SasPhyPage0_t *buffer;
1466 dma_addr_t dma_handle;
1467 int error;
1468
1469 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1470 hdr.ExtPageLength = 0;
1471 hdr.PageNumber = 0;
1472 hdr.Reserved1 = 0;
1473 hdr.Reserved2 = 0;
1474 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1475 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1476
1477 cfg.cfghdr.ehdr = &hdr;
1478 cfg.dir = 0; /* read */
1479 cfg.timeout = 10;
1480
1481 /* Get Phy Pg 0 for each Phy. */
1482 cfg.physAddr = -1;
1483 cfg.pageAddr = form + form_specific;
1484 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1485
1486 error = mpt_config(ioc, &cfg);
1487 if (error)
1488 goto out;
1489
1490 if (!hdr.ExtPageLength) {
1491 error = -ENXIO;
1492 goto out;
1493 }
1494
1495 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1496 &dma_handle);
1497 if (!buffer) {
1498 error = -ENOMEM;
1499 goto out;
1500 }
1501
1502 cfg.physAddr = dma_handle;
1503 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1504
1505 error = mpt_config(ioc, &cfg);
1506 if (error)
1507 goto out_free_consistent;
1508
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301509 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001510
1511 phy_info->hw_link_rate = buffer->HwLinkRate;
1512 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1513 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1514 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1515
1516 out_free_consistent:
1517 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1518 buffer, dma_handle);
1519 out:
1520 return error;
1521}
1522
1523static int
1524mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1525 u32 form, u32 form_specific)
1526{
1527 ConfigExtendedPageHeader_t hdr;
1528 CONFIGPARMS cfg;
1529 SasDevicePage0_t *buffer;
1530 dma_addr_t dma_handle;
1531 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001532 int error=0;
1533
1534 if (ioc->sas_discovery_runtime &&
1535 mptsas_is_end_device(device_info))
1536 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001537
1538 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1539 hdr.ExtPageLength = 0;
1540 hdr.PageNumber = 0;
1541 hdr.Reserved1 = 0;
1542 hdr.Reserved2 = 0;
1543 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1544 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1545
1546 cfg.cfghdr.ehdr = &hdr;
1547 cfg.pageAddr = form + form_specific;
1548 cfg.physAddr = -1;
1549 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1550 cfg.dir = 0; /* read */
1551 cfg.timeout = 10;
1552
Moore, Ericdb9c9172006-03-14 09:14:18 -07001553 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001554 error = mpt_config(ioc, &cfg);
1555 if (error)
1556 goto out;
1557 if (!hdr.ExtPageLength) {
1558 error = -ENXIO;
1559 goto out;
1560 }
1561
1562 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1563 &dma_handle);
1564 if (!buffer) {
1565 error = -ENOMEM;
1566 goto out;
1567 }
1568
1569 cfg.physAddr = dma_handle;
1570 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1571
1572 error = mpt_config(ioc, &cfg);
1573 if (error)
1574 goto out_free_consistent;
1575
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301576 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001577
1578 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001579 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001580 device_info->handle_enclosure =
1581 le16_to_cpu(buffer->EnclosureHandle);
1582 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001583 device_info->phy_id = buffer->PhyNum;
1584 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001585 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001586 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001587 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001588 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1589 device_info->sas_address = le64_to_cpu(sas_address);
1590 device_info->device_info =
1591 le32_to_cpu(buffer->DeviceInfo);
1592
1593 out_free_consistent:
1594 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1595 buffer, dma_handle);
1596 out:
1597 return error;
1598}
1599
1600static int
1601mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1602 u32 form, u32 form_specific)
1603{
1604 ConfigExtendedPageHeader_t hdr;
1605 CONFIGPARMS cfg;
1606 SasExpanderPage0_t *buffer;
1607 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001608 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001609
1610 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1611 hdr.ExtPageLength = 0;
1612 hdr.PageNumber = 0;
1613 hdr.Reserved1 = 0;
1614 hdr.Reserved2 = 0;
1615 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1616 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1617
1618 cfg.cfghdr.ehdr = &hdr;
1619 cfg.physAddr = -1;
1620 cfg.pageAddr = form + form_specific;
1621 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1622 cfg.dir = 0; /* read */
1623 cfg.timeout = 10;
1624
Moore, Ericdb9c9172006-03-14 09:14:18 -07001625 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001626 error = mpt_config(ioc, &cfg);
1627 if (error)
1628 goto out;
1629
1630 if (!hdr.ExtPageLength) {
1631 error = -ENXIO;
1632 goto out;
1633 }
1634
1635 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1636 &dma_handle);
1637 if (!buffer) {
1638 error = -ENOMEM;
1639 goto out;
1640 }
1641
1642 cfg.physAddr = dma_handle;
1643 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1644
1645 error = mpt_config(ioc, &cfg);
1646 if (error)
1647 goto out_free_consistent;
1648
1649 /* save config data */
1650 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001651 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001652 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001653 if (!port_info->phy_info) {
1654 error = -ENOMEM;
1655 goto out_free_consistent;
1656 }
1657
Eric Moore2ecce492007-01-29 09:47:08 -07001658 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001659 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001660 port_info->phy_info[i].handle =
1661 le16_to_cpu(buffer->DevHandle);
1662 }
Eric Moore547f9a22006-06-27 14:42:12 -06001663
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001664 out_free_consistent:
1665 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1666 buffer, dma_handle);
1667 out:
1668 return error;
1669}
1670
1671static int
1672mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1673 u32 form, u32 form_specific)
1674{
1675 ConfigExtendedPageHeader_t hdr;
1676 CONFIGPARMS cfg;
1677 SasExpanderPage1_t *buffer;
1678 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001679 int error=0;
1680
1681 if (ioc->sas_discovery_runtime &&
1682 mptsas_is_end_device(&phy_info->attached))
1683 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001684
1685 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1686 hdr.ExtPageLength = 0;
1687 hdr.PageNumber = 1;
1688 hdr.Reserved1 = 0;
1689 hdr.Reserved2 = 0;
1690 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1691 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1692
1693 cfg.cfghdr.ehdr = &hdr;
1694 cfg.physAddr = -1;
1695 cfg.pageAddr = form + form_specific;
1696 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1697 cfg.dir = 0; /* read */
1698 cfg.timeout = 10;
1699
1700 error = mpt_config(ioc, &cfg);
1701 if (error)
1702 goto out;
1703
1704 if (!hdr.ExtPageLength) {
1705 error = -ENXIO;
1706 goto out;
1707 }
1708
1709 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1710 &dma_handle);
1711 if (!buffer) {
1712 error = -ENOMEM;
1713 goto out;
1714 }
1715
1716 cfg.physAddr = dma_handle;
1717 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1718
1719 error = mpt_config(ioc, &cfg);
1720 if (error)
1721 goto out_free_consistent;
1722
1723
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301724 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001725
1726 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001727 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001728 phy_info->port_id = buffer->PhysicalPort;
1729 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1730 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1731 phy_info->hw_link_rate = buffer->HwLinkRate;
1732 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1733 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1734
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001735 out_free_consistent:
1736 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1737 buffer, dma_handle);
1738 out:
1739 return error;
1740}
1741
1742static void
1743mptsas_parse_device_info(struct sas_identify *identify,
1744 struct mptsas_devinfo *device_info)
1745{
1746 u16 protocols;
1747
1748 identify->sas_address = device_info->sas_address;
1749 identify->phy_identifier = device_info->phy_id;
1750
1751 /*
1752 * Fill in Phy Initiator Port Protocol.
1753 * Bits 6:3, more than one bit can be set, fall through cases.
1754 */
1755 protocols = device_info->device_info & 0x78;
1756 identify->initiator_port_protocols = 0;
1757 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1758 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1759 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1760 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1761 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1762 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1763 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1764 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1765
1766 /*
1767 * Fill in Phy Target Port Protocol.
1768 * Bits 10:7, more than one bit can be set, fall through cases.
1769 */
1770 protocols = device_info->device_info & 0x780;
1771 identify->target_port_protocols = 0;
1772 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1773 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1774 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1775 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1776 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1777 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1778 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1779 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1780
1781 /*
1782 * Fill in Attached device type.
1783 */
1784 switch (device_info->device_info &
1785 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1786 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1787 identify->device_type = SAS_PHY_UNUSED;
1788 break;
1789 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1790 identify->device_type = SAS_END_DEVICE;
1791 break;
1792 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1793 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1794 break;
1795 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1796 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1797 break;
1798 }
1799}
1800
1801static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001802 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001803{
Moore, Erice6b2d762006-03-14 09:14:24 -07001804 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001805 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001806 struct sas_port *port;
1807 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001808
Eric Moore547f9a22006-06-27 14:42:12 -06001809 if (!dev) {
1810 error = -ENODEV;
1811 goto out;
1812 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001813
1814 if (!phy_info->phy) {
1815 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001816 if (!phy) {
1817 error = -ENOMEM;
1818 goto out;
1819 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001820 } else
1821 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001822
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001823 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
1825 /*
1826 * Set Negotiated link rate.
1827 */
1828 switch (phy_info->negotiated_link_rate) {
1829 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001830 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001831 break;
1832 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001833 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001834 break;
1835 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001836 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001837 break;
1838 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001839 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840 break;
1841 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1842 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1843 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001844 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001845 break;
1846 }
1847
1848 /*
1849 * Set Max hardware link rate.
1850 */
1851 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1852 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001853 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854 break;
1855 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001856 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857 break;
1858 default:
1859 break;
1860 }
1861
1862 /*
1863 * Set Max programmed link rate.
1864 */
1865 switch (phy_info->programmed_link_rate &
1866 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1867 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001868 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001869 break;
1870 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001871 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001872 break;
1873 default:
1874 break;
1875 }
1876
1877 /*
1878 * Set Min hardware link rate.
1879 */
1880 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1881 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001882 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001883 break;
1884 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001885 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001886 break;
1887 default:
1888 break;
1889 }
1890
1891 /*
1892 * Set Min programmed link rate.
1893 */
1894 switch (phy_info->programmed_link_rate &
1895 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1896 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001897 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001898 break;
1899 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001900 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001901 break;
1902 default:
1903 break;
1904 }
1905
Moore, Erice6b2d762006-03-14 09:14:24 -07001906 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001907
Moore, Erice6b2d762006-03-14 09:14:24 -07001908 error = sas_phy_add(phy);
1909 if (error) {
1910 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001911 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001912 }
1913 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001914 }
1915
Eric Moore547f9a22006-06-27 14:42:12 -06001916 if (!phy_info->attached.handle ||
1917 !phy_info->port_details)
1918 goto out;
1919
1920 port = mptsas_get_port(phy_info);
1921 ioc = phy_to_ioc(phy_info->phy);
1922
1923 if (phy_info->sas_port_add_phy) {
1924
1925 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001926 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001927 if (!port) {
1928 error = -ENOMEM;
1929 goto out;
1930 }
1931 error = sas_port_add(port);
1932 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301933 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001934 "%s: exit at line=%d\n", ioc->name,
1935 __FUNCTION__, __LINE__));
1936 goto out;
1937 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301938 mptsas_set_port(ioc, phy_info, port);
1939 dsaswideprintk(ioc, printk(KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -06001940 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1941 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001942 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301943 dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
Eric Moore547f9a22006-06-27 14:42:12 -06001944 phy_info->phy_id));
1945 sas_port_add_phy(port, phy_info->phy);
1946 phy_info->sas_port_add_phy = 0;
1947 }
1948
1949 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001950
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001951 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001952 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001953 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001954
James Bottomley2686de22006-06-30 12:54:02 -05001955 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001956 /*
1957 * Let the hotplug_work thread handle processing
1958 * the adding/removing of devices that occur
1959 * after start of day.
1960 */
1961 if (ioc->sas_discovery_runtime &&
1962 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001963 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001964
James Bottomleyf013db32006-03-18 14:54:36 -06001965 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001966 if (scsi_is_host_device(parent)) {
1967 struct mptsas_portinfo *port_info;
1968 int i;
1969
1970 mutex_lock(&ioc->sas_topology_mutex);
1971 port_info = mptsas_find_portinfo_by_handle(ioc,
1972 ioc->handle);
1973 mutex_unlock(&ioc->sas_topology_mutex);
1974
1975 for (i = 0; i < port_info->num_phys; i++)
1976 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001977 identify.sas_address) {
1978 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001979 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001980 }
James Bottomley2686de22006-06-30 12:54:02 -05001981
1982 } else if (scsi_is_sas_rphy(parent)) {
1983 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
1984 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001985 parent_rphy->identify.sas_address) {
1986 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001987 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001988 }
James Bottomley2686de22006-06-30 12:54:02 -05001989 }
1990
James Bottomleyf013db32006-03-18 14:54:36 -06001991 switch (identify.device_type) {
1992 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001993 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06001994 break;
1995 case SAS_EDGE_EXPANDER_DEVICE:
1996 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001997 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06001998 break;
1999 default:
2000 rphy = NULL;
2001 break;
2002 }
Eric Moore547f9a22006-06-27 14:42:12 -06002003 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302004 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002005 "%s: exit at line=%d\n", ioc->name,
2006 __FUNCTION__, __LINE__));
2007 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002008 }
2009
Eric Moore547f9a22006-06-27 14:42:12 -06002010 rphy->identify = identify;
2011 error = sas_rphy_add(rphy);
2012 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302013 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002014 "%s: exit at line=%d\n", ioc->name,
2015 __FUNCTION__, __LINE__));
2016 sas_rphy_free(rphy);
2017 goto out;
2018 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302019 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002020 }
2021
Eric Moore547f9a22006-06-27 14:42:12 -06002022 out:
2023 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002024}
2025
2026static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002027mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002028{
Moore, Erice6b2d762006-03-14 09:14:24 -07002029 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002030 int error = -ENOMEM, i;
2031
Moore, Erice6b2d762006-03-14 09:14:24 -07002032 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2033 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002034 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002035
Moore, Erice6b2d762006-03-14 09:14:24 -07002036 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002037 if (error)
2038 goto out_free_port_info;
2039
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302040 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002041 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002042 ioc->handle = hba->phy_info[0].handle;
2043 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002044 if (!port_info) {
2045 port_info = hba;
2046 list_add_tail(&port_info->list, &ioc->sas_topology);
2047 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002048 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002049 port_info->phy_info[i].negotiated_link_rate =
2050 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002051 port_info->phy_info[i].handle =
2052 hba->phy_info[i].handle;
2053 port_info->phy_info[i].port_id =
2054 hba->phy_info[i].port_id;
2055 }
Eric Moore547f9a22006-06-27 14:42:12 -06002056 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002057 kfree(hba);
2058 hba = NULL;
2059 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002060 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002061 for (i = 0; i < port_info->num_phys; i++) {
2062 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2063 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2064 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2065
2066 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002067 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2068 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2069 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002070 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002071 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002072 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002073 mptsas_sas_device_pg0(ioc,
2074 &port_info->phy_info[i].attached,
2075 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2076 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2077 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002078 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002079
Eric Moore547f9a22006-06-27 14:42:12 -06002080 mptsas_setup_wide_ports(ioc, port_info);
2081
2082 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002083 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002084 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085
2086 return 0;
2087
2088 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002089 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002090 out:
2091 return error;
2092}
2093
2094static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002095mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002096{
Moore, Erice6b2d762006-03-14 09:14:24 -07002097 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002098 struct device *parent;
2099 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002100 int error = -ENOMEM, i, j;
2101
Moore, Erice6b2d762006-03-14 09:14:24 -07002102 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2103 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002104 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002105
Moore, Erice6b2d762006-03-14 09:14:24 -07002106 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002107 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2108 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002109 if (error)
2110 goto out_free_port_info;
2111
Eric Moore2ecce492007-01-29 09:47:08 -07002112 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002113
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002114 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002115 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2116 if (!port_info) {
2117 port_info = ex;
2118 list_add_tail(&port_info->list, &ioc->sas_topology);
2119 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002120 for (i = 0; i < ex->num_phys; i++) {
2121 port_info->phy_info[i].handle =
2122 ex->phy_info[i].handle;
2123 port_info->phy_info[i].port_id =
2124 ex->phy_info[i].port_id;
2125 }
Eric Moore547f9a22006-06-27 14:42:12 -06002126 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002127 kfree(ex);
2128 ex = NULL;
2129 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002130 mutex_unlock(&ioc->sas_topology_mutex);
2131
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002132 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002133 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2134 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2135 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2136
2137 if (port_info->phy_info[i].identify.handle) {
2138 mptsas_sas_device_pg0(ioc,
2139 &port_info->phy_info[i].identify,
2140 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2141 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2142 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002143 port_info->phy_info[i].identify.phy_id =
2144 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002145 }
2146
2147 if (port_info->phy_info[i].attached.handle) {
2148 mptsas_sas_device_pg0(ioc,
2149 &port_info->phy_info[i].attached,
2150 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2151 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2152 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002153 port_info->phy_info[i].attached.phy_id =
2154 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002155 }
Eric Moore547f9a22006-06-27 14:42:12 -06002156 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002157
Eric Moore547f9a22006-06-27 14:42:12 -06002158 parent = &ioc->sh->shost_gendev;
2159 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002160 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002161 list_for_each_entry(p, &ioc->sas_topology, list) {
2162 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002163 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002164 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002165 continue;
2166 rphy = mptsas_get_rphy(&p->phy_info[j]);
2167 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002168 }
2169 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002170 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002171 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002172
Eric Moore547f9a22006-06-27 14:42:12 -06002173 mptsas_setup_wide_ports(ioc, port_info);
2174
2175 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002176 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002177 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002178
2179 return 0;
2180
2181 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002182 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002183 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002184 kfree(ex);
2185 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002186 out:
2187 return error;
2188}
2189
Moore, Erice6b2d762006-03-14 09:14:24 -07002190/*
2191 * mptsas_delete_expander_phys
2192 *
2193 *
2194 * This will traverse topology, and remove expanders
2195 * that are no longer present
2196 */
2197static void
2198mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2199{
2200 struct mptsas_portinfo buffer;
2201 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002202 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002203 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002204 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002205 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002206
2207 mutex_lock(&ioc->sas_topology_mutex);
2208 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2209
2210 if (port_info->phy_info &&
2211 (!(port_info->phy_info[0].identify.device_info &
2212 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2213 continue;
2214
2215 if (mptsas_sas_expander_pg0(ioc, &buffer,
2216 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002217 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2218 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002219
2220 /*
2221 * Obtain the port_info instance to the parent port
2222 */
2223 parent = mptsas_find_portinfo_by_handle(ioc,
2224 port_info->phy_info[0].identify.handle_parent);
2225
2226 if (!parent)
2227 goto next_port;
2228
Eric Moore547f9a22006-06-27 14:42:12 -06002229 expander_sas_address =
2230 port_info->phy_info[0].identify.sas_address;
2231
Moore, Erice6b2d762006-03-14 09:14:24 -07002232 /*
2233 * Delete rphys in the parent that point
2234 * to this expander. The transport layer will
2235 * cleanup all the children.
2236 */
Eric Moore547f9a22006-06-27 14:42:12 -06002237 phy_info = parent->phy_info;
2238 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2239 port = mptsas_get_port(phy_info);
2240 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002241 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002242 if (phy_info->attached.sas_address !=
2243 expander_sas_address)
2244 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302245 dsaswideprintk(ioc,
2246 dev_printk(KERN_DEBUG, &port->dev,
2247 "delete port (%d)\n", port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002248 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302249 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002250 }
2251 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002252
2253 phy_info = port_info->phy_info;
2254 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302255 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002256
Moore, Erice6b2d762006-03-14 09:14:24 -07002257 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002258 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002259 kfree(port_info);
2260 }
2261 /*
2262 * Free this memory allocated from inside
2263 * mptsas_sas_expander_pg0
2264 */
Eric Moore547f9a22006-06-27 14:42:12 -06002265 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002266 }
2267 mutex_unlock(&ioc->sas_topology_mutex);
2268}
2269
2270/*
2271 * Start of day discovery
2272 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002273static void
2274mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2275{
2276 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002277 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002278
Moore, Erice6b2d762006-03-14 09:14:24 -07002279 mutex_lock(&ioc->sas_discovery_mutex);
2280 mptsas_probe_hba_phys(ioc);
2281 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002282 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002283 /*
2284 Reporting RAID volumes.
2285 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002286 if (!ioc->ir_firmware)
2287 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002288 if (!ioc->raid_data.pIocPg2)
2289 goto out;
2290 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2291 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002292 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002293 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002294 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2295 }
2296 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002297 mutex_unlock(&ioc->sas_discovery_mutex);
2298}
2299
2300/*
2301 * Work queue thread to handle Runtime discovery
2302 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002303 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002304 */
2305static void
Eric Moore547f9a22006-06-27 14:42:12 -06002306__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002307{
Moore, Erice6b2d762006-03-14 09:14:24 -07002308 u32 handle = 0xFFFF;
2309
Moore, Erice6b2d762006-03-14 09:14:24 -07002310 ioc->sas_discovery_runtime=1;
2311 mptsas_delete_expander_phys(ioc);
2312 mptsas_probe_hba_phys(ioc);
2313 while (!mptsas_probe_expander_phys(ioc, &handle))
2314 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002315 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002316}
2317
2318/*
2319 * Work queue thread to handle Runtime discovery
2320 * Mere purpose is the hot add/delete of expanders
2321 *(Mutex LOCKED)
2322 */
2323static void
David Howellsc4028952006-11-22 14:57:56 +00002324mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002325{
David Howellsc4028952006-11-22 14:57:56 +00002326 struct mptsas_discovery_event *ev =
2327 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002328 MPT_ADAPTER *ioc = ev->ioc;
2329
2330 mutex_lock(&ioc->sas_discovery_mutex);
2331 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002332 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002333 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002334}
2335
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002336static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002337mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002338{
2339 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002340 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002341 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002342
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002343 mutex_lock(&ioc->sas_topology_mutex);
2344 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2345 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002346 if (!mptsas_is_end_device(
2347 &port_info->phy_info[i].attached))
2348 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002349 if (port_info->phy_info[i].attached.sas_address
2350 != sas_address)
2351 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002352 phy_info = &port_info->phy_info[i];
2353 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002354 }
2355 }
2356 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002357 return phy_info;
2358}
2359
2360static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002361mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002362{
2363 struct mptsas_portinfo *port_info;
2364 struct mptsas_phyinfo *phy_info = NULL;
2365 int i;
2366
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002367 mutex_lock(&ioc->sas_topology_mutex);
2368 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002369 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002370 if (!mptsas_is_end_device(
2371 &port_info->phy_info[i].attached))
2372 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002373 if (port_info->phy_info[i].attached.id != id)
2374 continue;
2375 if (port_info->phy_info[i].attached.channel != channel)
2376 continue;
2377 phy_info = &port_info->phy_info[i];
2378 break;
2379 }
2380 }
2381 mutex_unlock(&ioc->sas_topology_mutex);
2382 return phy_info;
2383}
2384
2385static struct mptsas_phyinfo *
2386mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2387{
2388 struct mptsas_portinfo *port_info;
2389 struct mptsas_phyinfo *phy_info = NULL;
2390 int i;
2391
2392 mutex_lock(&ioc->sas_topology_mutex);
2393 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2394 for (i = 0; i < port_info->num_phys; i++) {
2395 if (!mptsas_is_end_device(
2396 &port_info->phy_info[i].attached))
2397 continue;
2398 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2399 continue;
2400 if (port_info->phy_info[i].attached.phys_disk_num != id)
2401 continue;
2402 if (port_info->phy_info[i].attached.channel != channel)
2403 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002404 phy_info = &port_info->phy_info[i];
2405 break;
2406 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002407 }
2408 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002409 return phy_info;
2410}
2411
Moore, Eric4b766472006-03-14 09:14:12 -07002412/*
2413 * Work queue thread to clear the persitency table
2414 */
2415static void
David Howellsc4028952006-11-22 14:57:56 +00002416mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002417{
David Howellsc4028952006-11-22 14:57:56 +00002418 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002419
2420 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2421}
2422
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002423static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002424mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2425{
Eric Mooref99be432007-01-04 20:46:54 -07002426 int rc;
2427
Moore, Ericf44e5462006-03-14 09:14:21 -07002428 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002429 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002430}
2431
2432static void
2433mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2434{
2435 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2436 mptsas_reprobe_lun);
2437}
2438
Eric Mooreb506ade2007-01-29 09:45:37 -07002439static void
2440mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2441{
2442 CONFIGPARMS cfg;
2443 ConfigPageHeader_t hdr;
2444 dma_addr_t dma_handle;
2445 pRaidVolumePage0_t buffer = NULL;
2446 RaidPhysDiskPage0_t phys_disk;
2447 int i;
2448 struct mptsas_hotplug_event *ev;
2449
2450 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2451 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2452 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2453 cfg.pageAddr = (channel << 8) + id;
2454 cfg.cfghdr.hdr = &hdr;
2455 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2456
2457 if (mpt_config(ioc, &cfg) != 0)
2458 goto out;
2459
2460 if (!hdr.PageLength)
2461 goto out;
2462
2463 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2464 &dma_handle);
2465
2466 if (!buffer)
2467 goto out;
2468
2469 cfg.physAddr = dma_handle;
2470 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2471
2472 if (mpt_config(ioc, &cfg) != 0)
2473 goto out;
2474
2475 if (!(buffer->VolumeStatus.Flags &
2476 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2477 goto out;
2478
2479 if (!buffer->NumPhysDisks)
2480 goto out;
2481
2482 for (i = 0; i < buffer->NumPhysDisks; i++) {
2483
2484 if (mpt_raid_phys_disk_pg0(ioc,
2485 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2486 continue;
2487
2488 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2489 if (!ev) {
2490 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2491 goto out;
2492 }
2493
2494 INIT_WORK(&ev->work, mptsas_hotplug_work);
2495 ev->ioc = ioc;
2496 ev->id = phys_disk.PhysDiskID;
2497 ev->channel = phys_disk.PhysDiskBus;
2498 ev->phys_disk_num_valid = 1;
2499 ev->phys_disk_num = phys_disk.PhysDiskNum;
2500 ev->event_type = MPTSAS_ADD_DEVICE;
2501 schedule_work(&ev->work);
2502 }
2503
2504 out:
2505 if (buffer)
2506 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2507 dma_handle);
2508}
Moore, Erice6b2d762006-03-14 09:14:24 -07002509/*
2510 * Work queue thread to handle SAS hotplug events
2511 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002512static void
David Howellsc4028952006-11-22 14:57:56 +00002513mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002514{
David Howellsc4028952006-11-22 14:57:56 +00002515 struct mptsas_hotplug_event *ev =
2516 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002517
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002518 MPT_ADAPTER *ioc = ev->ioc;
2519 struct mptsas_phyinfo *phy_info;
2520 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002521 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002522 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002523 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002524 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002525 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002526 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002527 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002528 VirtDevice *vdevice;
2529
Moore, Erice6b2d762006-03-14 09:14:24 -07002530 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002531 switch (ev->event_type) {
2532 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002533
Eric Mooreb506ade2007-01-29 09:45:37 -07002534 phy_info = NULL;
2535 if (ev->phys_disk_num_valid) {
2536 if (ev->hidden_raid_component){
2537 if (mptsas_sas_device_pg0(ioc, &sas_device,
2538 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2539 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2540 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302541 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002542 "%s: exit at line=%d\n", ioc->name,
2543 __FUNCTION__, __LINE__));
2544 break;
2545 }
2546 phy_info = mptsas_find_phyinfo_by_sas_address(
2547 ioc, sas_device.sas_address);
2548 }else
2549 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2550 ioc, ev->channel, ev->phys_disk_num);
2551 }
2552
2553 if (!phy_info)
2554 phy_info = mptsas_find_phyinfo_by_target(ioc,
2555 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002556
Moore, Ericf44e5462006-03-14 09:14:21 -07002557 /*
2558 * Sanity checks, for non-existing phys and remote rphys.
2559 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002560 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302561 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002562 "%s: exit at line=%d\n", ioc->name,
2563 __FUNCTION__, __LINE__));
2564 break;
2565 }
2566 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302567 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002568 "%s: exit at line=%d\n", ioc->name,
2569 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002570 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002571 }
2572 rphy = mptsas_get_rphy(phy_info);
2573 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302574 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002575 "%s: exit at line=%d\n", ioc->name,
2576 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002577 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002578 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002579
Eric Moore547f9a22006-06-27 14:42:12 -06002580 port = mptsas_get_port(phy_info);
2581 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302582 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002583 "%s: exit at line=%d\n", ioc->name,
2584 __FUNCTION__, __LINE__));
2585 break;
2586 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002587
Eric Moore547f9a22006-06-27 14:42:12 -06002588 starget = mptsas_get_starget(phy_info);
2589 if (starget) {
2590 vtarget = starget->hostdata;
2591
2592 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302593 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002594 "%s: exit at line=%d\n", ioc->name,
2595 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002596 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002597 }
2598
Moore, Ericf44e5462006-03-14 09:14:21 -07002599 /*
2600 * Handling RAID components
2601 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002602 if (ev->phys_disk_num_valid &&
2603 ev->hidden_raid_component) {
2604 printk(MYIOC_s_INFO_FMT
2605 "RAID Hidding: channel=%d, id=%d, "
2606 "physdsk %d \n", ioc->name, ev->channel,
2607 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002608 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002609 vtarget->tflags |=
2610 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002611 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002612 phy_info->attached.phys_disk_num =
2613 ev->phys_disk_num;
2614 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002615 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002616 }
2617
Eric Mooreb506ade2007-01-29 09:45:37 -07002618 if (phy_info->attached.device_info &
2619 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002620 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002621 if (phy_info->attached.device_info &
2622 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002623 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002624 if (phy_info->attached.device_info &
2625 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002626 ds = "sata";
2627
2628 printk(MYIOC_s_INFO_FMT
2629 "removing %s device, channel %d, id %d, phy %d\n",
2630 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Mooredc22f162006-07-06 11:23:14 -06002631 dev_printk(KERN_DEBUG, &port->dev,
2632 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002633 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302634 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002635 break;
2636 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002637
Moore, Ericbd23e942006-04-17 12:43:04 -06002638 if (ev->phys_disk_num_valid)
2639 mpt_findImVolumes(ioc);
2640
Moore, Ericc73787ee2006-01-26 16:20:06 -07002641 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002642 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002643 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002644 if (mptsas_sas_device_pg0(ioc, &sas_device,
2645 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002646 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2647 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302648 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002649 "%s: exit at line=%d\n", ioc->name,
2650 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002651 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002652 }
2653
Eric Moore547f9a22006-06-27 14:42:12 -06002654 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002655
Eric Moore547f9a22006-06-27 14:42:12 -06002656 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2657 sas_device.sas_address);
2658
2659 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302660 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002661 "%s: exit at line=%d\n", ioc->name,
2662 __FUNCTION__, __LINE__));
2663 break;
2664 }
2665
2666 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002667 if (starget && (!ev->hidden_raid_component)){
2668
Eric Moore547f9a22006-06-27 14:42:12 -06002669 vtarget = starget->hostdata;
2670
2671 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302672 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002673 "%s: exit at line=%d\n", ioc->name,
2674 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002675 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002676 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002677 /*
2678 * Handling RAID components
2679 */
2680 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002681 printk(MYIOC_s_INFO_FMT
2682 "RAID Exposing: channel=%d, id=%d, "
2683 "physdsk %d \n", ioc->name, ev->channel,
2684 ev->id, ev->phys_disk_num);
2685 vtarget->tflags &=
2686 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002687 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002688 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002689 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002690 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002691 break;
2692 }
2693
Eric Moore547f9a22006-06-27 14:42:12 -06002694 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302695 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002696 "%s: exit at line=%d\n", ioc->name,
2697 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002698 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002699 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002700 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002701
Eric Moore547f9a22006-06-27 14:42:12 -06002702 port = mptsas_get_port(phy_info);
2703 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302704 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002705 "%s: exit at line=%d\n", ioc->name,
2706 __FUNCTION__, __LINE__));
2707 break;
2708 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002709 memcpy(&phy_info->attached, &sas_device,
2710 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002711
Eric Mooreb506ade2007-01-29 09:45:37 -07002712 if (phy_info->attached.device_info &
2713 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002714 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002715 if (phy_info->attached.device_info &
2716 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002717 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002718 if (phy_info->attached.device_info &
2719 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002720 ds = "sata";
2721
2722 printk(MYIOC_s_INFO_FMT
2723 "attaching %s device, channel %d, id %d, phy %d\n",
2724 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2725
James Bottomleyf013db32006-03-18 14:54:36 -06002726 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002727 rphy = sas_end_device_alloc(port);
2728 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302729 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002730 "%s: exit at line=%d\n", ioc->name,
2731 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002732 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002733 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002734
James Bottomleyf013db32006-03-18 14:54:36 -06002735 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002736 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302737 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002738 "%s: exit at line=%d\n", ioc->name,
2739 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002740 sas_rphy_free(rphy);
2741 break;
2742 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302743 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002744 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002745 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002746 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2747 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002748 if (sdev) {
2749 scsi_device_put(sdev);
2750 break;
2751 }
2752 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002753 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002754 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2755 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002756 mpt_findImVolumes(ioc);
2757 break;
2758 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002759 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002760 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002761 if (!sdev)
2762 break;
2763 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002764 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002765 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002766 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002767 scsi_remove_device(sdev);
2768 scsi_device_put(sdev);
2769 mpt_findImVolumes(ioc);
2770 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002771 case MPTSAS_ADD_INACTIVE_VOLUME:
2772 mptsas_adding_inactive_raid_components(ioc,
2773 ev->channel, ev->id);
2774 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002775 case MPTSAS_IGNORE_EVENT:
2776 default:
2777 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002778 }
2779
Moore, Erice6b2d762006-03-14 09:14:24 -07002780 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002781 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002782}
2783
2784static void
Eric Moore547f9a22006-06-27 14:42:12 -06002785mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002786 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2787{
2788 struct mptsas_hotplug_event *ev;
2789 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2790 __le64 sas_address;
2791
2792 if ((device_info &
2793 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2794 MPI_SAS_DEVICE_INFO_STP_TARGET |
2795 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2796 return;
2797
Moore, Eric4b766472006-03-14 09:14:12 -07002798 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002799 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002800
2801 mptsas_target_reset_queue(ioc, sas_event_data);
2802 break;
2803
2804 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002805 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002806 if (!ev) {
2807 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2808 break;
2809 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002810
David Howellsc4028952006-11-22 14:57:56 +00002811 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002812 ev->ioc = ioc;
2813 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2814 ev->parent_handle =
2815 le16_to_cpu(sas_event_data->ParentDevHandle);
2816 ev->channel = sas_event_data->Bus;
2817 ev->id = sas_event_data->TargetID;
2818 ev->phy_id = sas_event_data->PhyNum;
2819 memcpy(&sas_address, &sas_event_data->SASAddress,
2820 sizeof(__le64));
2821 ev->sas_address = le64_to_cpu(sas_address);
2822 ev->device_info = device_info;
2823
2824 if (sas_event_data->ReasonCode &
2825 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2826 ev->event_type = MPTSAS_ADD_DEVICE;
2827 else
2828 ev->event_type = MPTSAS_DEL_DEVICE;
2829 schedule_work(&ev->work);
2830 break;
2831 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2832 /*
2833 * Persistent table is full.
2834 */
Eric Moore547f9a22006-06-27 14:42:12 -06002835 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002836 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002837 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002838 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002839 /*
2840 * TODO, handle other events
2841 */
Moore, Eric4b766472006-03-14 09:14:12 -07002842 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002843 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002844 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002845 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2846 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2847 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2848 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002849 default:
2850 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002851 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002852}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002853static void
Eric Moore547f9a22006-06-27 14:42:12 -06002854mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002855 EVENT_DATA_RAID *raid_event_data)
2856{
2857 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002858 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2859 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002860
2861 if (ioc->bus_type != SAS)
2862 return;
2863
Eric Moore547f9a22006-06-27 14:42:12 -06002864 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002865 if (!ev) {
2866 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2867 return;
2868 }
2869
David Howellsc4028952006-11-22 14:57:56 +00002870 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002871 ev->ioc = ioc;
2872 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002873 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002874 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002875
2876 switch (raid_event_data->ReasonCode) {
2877 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002878 ev->phys_disk_num_valid = 1;
2879 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002880 ev->event_type = MPTSAS_ADD_DEVICE;
2881 break;
2882 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002883 ev->phys_disk_num_valid = 1;
2884 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002885 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002886 ev->event_type = MPTSAS_DEL_DEVICE;
2887 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002888 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2889 switch (state) {
2890 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002891 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002892 ev->phys_disk_num_valid = 1;
2893 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002894 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002895 ev->event_type = MPTSAS_ADD_DEVICE;
2896 break;
2897 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002898 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2899 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2900 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002901 ev->phys_disk_num_valid = 1;
2902 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002903 ev->event_type = MPTSAS_DEL_DEVICE;
2904 break;
2905 default:
2906 break;
2907 }
2908 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002909 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2910 ev->event_type = MPTSAS_DEL_RAID;
2911 break;
2912 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2913 ev->event_type = MPTSAS_ADD_RAID;
2914 break;
2915 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002916 switch (state) {
2917 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2918 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2919 ev->event_type = MPTSAS_DEL_RAID;
2920 break;
2921 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2922 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2923 ev->event_type = MPTSAS_ADD_RAID;
2924 break;
2925 default:
2926 break;
2927 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002928 break;
2929 default:
2930 break;
2931 }
2932 schedule_work(&ev->work);
2933}
2934
Moore, Erice6b2d762006-03-14 09:14:24 -07002935static void
Eric Moore547f9a22006-06-27 14:42:12 -06002936mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002937 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2938{
2939 struct mptsas_discovery_event *ev;
2940
2941 /*
2942 * DiscoveryStatus
2943 *
2944 * This flag will be non-zero when firmware
2945 * kicks off discovery, and return to zero
2946 * once its completed.
2947 */
2948 if (discovery_data->DiscoveryStatus)
2949 return;
2950
Eric Moore547f9a22006-06-27 14:42:12 -06002951 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002952 if (!ev)
2953 return;
David Howellsc4028952006-11-22 14:57:56 +00002954 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002955 ev->ioc = ioc;
2956 schedule_work(&ev->work);
2957};
2958
Eric Mooreb506ade2007-01-29 09:45:37 -07002959/*
2960 * mptsas_send_ir2_event - handle exposing hidden disk when
2961 * an inactive raid volume is added
2962 *
2963 * @ioc: Pointer to MPT_ADAPTER structure
2964 * @ir2_data
2965 *
2966 */
2967static void
2968mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2969{
2970 struct mptsas_hotplug_event *ev;
2971
2972 if (ir2_data->ReasonCode !=
2973 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2974 return;
2975
2976 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2977 if (!ev)
2978 return;
2979
2980 INIT_WORK(&ev->work, mptsas_hotplug_work);
2981 ev->ioc = ioc;
2982 ev->id = ir2_data->TargetID;
2983 ev->channel = ir2_data->Bus;
2984 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
2985
2986 schedule_work(&ev->work);
2987};
Moore, Erice6b2d762006-03-14 09:14:24 -07002988
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002989static int
2990mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2991{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002992 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002993 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2994
2995 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002996 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002997
Moore, Erice6b2d762006-03-14 09:14:24 -07002998 /*
2999 * sas_discovery_ignore_events
3000 *
3001 * This flag is to prevent anymore processing of
3002 * sas events once mptsas_remove function is called.
3003 */
3004 if (ioc->sas_discovery_ignore_events) {
3005 rc = mptscsih_event_process(ioc, reply);
3006 goto out;
3007 }
3008
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003009 switch (event) {
3010 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003011 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003012 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003013 break;
3014 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003015 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003016 (EVENT_DATA_RAID *)reply->Data);
3017 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003018 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003019 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003020 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003021 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003022 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003023 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003024 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003025 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3026 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003027 case MPI_EVENT_IR2:
3028 mptsas_send_ir2_event(ioc,
3029 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3030 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003031 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003032 rc = mptscsih_event_process(ioc, reply);
3033 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003034 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003035 out:
3036
3037 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003038}
3039
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003040static int
3041mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3042{
3043 struct Scsi_Host *sh;
3044 MPT_SCSI_HOST *hd;
3045 MPT_ADAPTER *ioc;
3046 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003047 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003048 int numSGE = 0;
3049 int scale;
3050 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003051 int error=0;
3052 int r;
3053
3054 r = mpt_attach(pdev,id);
3055 if (r)
3056 return r;
3057
3058 ioc = pci_get_drvdata(pdev);
3059 ioc->DoneCtx = mptsasDoneCtx;
3060 ioc->TaskCtx = mptsasTaskCtx;
3061 ioc->InternalCtx = mptsasInternalCtx;
3062
3063 /* Added sanity check on readiness of the MPT adapter.
3064 */
3065 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3066 printk(MYIOC_s_WARN_FMT
3067 "Skipping because it's not operational!\n",
3068 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003069 error = -ENODEV;
3070 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003071 }
3072
3073 if (!ioc->active) {
3074 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3075 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003076 error = -ENODEV;
3077 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003078 }
3079
3080 /* Sanity check - ensure at least 1 port is INITIATOR capable
3081 */
3082 ioc_cap = 0;
3083 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3084 if (ioc->pfacts[ii].ProtocolFlags &
3085 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3086 ioc_cap++;
3087 }
3088
3089 if (!ioc_cap) {
3090 printk(MYIOC_s_WARN_FMT
3091 "Skipping ioc=%p because SCSI Initiator mode "
3092 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003093 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003094 }
3095
3096 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3097 if (!sh) {
3098 printk(MYIOC_s_WARN_FMT
3099 "Unable to register controller with SCSI subsystem\n",
3100 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003101 error = -1;
3102 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003103 }
3104
3105 spin_lock_irqsave(&ioc->FreeQlock, flags);
3106
3107 /* Attach the SCSI Host to the IOC structure
3108 */
3109 ioc->sh = sh;
3110
3111 sh->io_port = 0;
3112 sh->n_io_port = 0;
3113 sh->irq = 0;
3114
3115 /* set 16 byte cdb's */
3116 sh->max_cmd_len = 16;
3117
Eric Moore793955f2007-01-29 09:42:20 -07003118 sh->max_id = ioc->pfacts[0].PortSCSIID;
3119 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003120
3121 sh->transportt = mptsas_transport_template;
3122
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003123 sh->this_id = ioc->pfacts[0].PortSCSIID;
3124
3125 /* Required entry.
3126 */
3127 sh->unique_id = ioc->id;
3128
3129 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003130 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003131 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003132 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003133 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003134
3135 /* Verify that we won't exceed the maximum
3136 * number of chain buffers
3137 * We can optimize: ZZ = req_sz/sizeof(SGE)
3138 * For 32bit SGE's:
3139 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3140 * + (req_sz - 64)/sizeof(SGE)
3141 * A slightly different algorithm is required for
3142 * 64bit SGEs.
3143 */
3144 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3145 if (sizeof(dma_addr_t) == sizeof(u64)) {
3146 numSGE = (scale - 1) *
3147 (ioc->facts.MaxChainDepth-1) + scale +
3148 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3149 sizeof(u32));
3150 } else {
3151 numSGE = 1 + (scale - 1) *
3152 (ioc->facts.MaxChainDepth-1) + scale +
3153 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3154 sizeof(u32));
3155 }
3156
3157 if (numSGE < sh->sg_tablesize) {
3158 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303159 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003160 "Resetting sg_tablesize to %d from %d\n",
3161 ioc->name, numSGE, sh->sg_tablesize));
3162 sh->sg_tablesize = numSGE;
3163 }
3164
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003165 hd = (MPT_SCSI_HOST *) sh->hostdata;
3166 hd->ioc = ioc;
3167
3168 /* SCSI needs scsi_cmnd lookup table!
3169 * (with size equal to req_depth*PtrSz!)
3170 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003171 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3172 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003173 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003174 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003175 }
3176
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303177 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003178 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003179
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003180 /* Clear the TM flags
3181 */
3182 hd->tmPending = 0;
3183 hd->tmState = TM_STATE_NONE;
3184 hd->resetPending = 0;
3185 hd->abortSCpnt = NULL;
3186
3187 /* Clear the pointer used to store
3188 * single-threaded commands, i.e., those
3189 * issued during a bus scan, dv and
3190 * configuration pages.
3191 */
3192 hd->cmdPtr = NULL;
3193
3194 /* Initialize this SCSI Hosts' timers
3195 * To use, set the timer expires field
3196 * and add_timer
3197 */
3198 init_timer(&hd->timer);
3199 hd->timer.data = (unsigned long) hd;
3200 hd->timer.function = mptscsih_timer_expired;
3201
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003202 ioc->sas_data.ptClear = mpt_pt_clear;
3203
Eric Mooredf9e0622007-01-29 09:46:21 -07003204 init_waitqueue_head(&hd->scandv_waitq);
3205 hd->scandv_wait_done = 0;
3206 hd->last_queue_full = 0;
3207 INIT_LIST_HEAD(&hd->target_reset_list);
3208 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3209
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003210 if (ioc->sas_data.ptClear==1) {
3211 mptbase_sas_persist_operation(
3212 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3213 }
3214
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003215 error = scsi_add_host(sh, &ioc->pcidev->dev);
3216 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303217 dprintk(ioc, printk(KERN_ERR MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003218 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003219 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003220 }
3221
3222 mptsas_scan_sas_topology(ioc);
3223
3224 return 0;
3225
Eric Moore547f9a22006-06-27 14:42:12 -06003226 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003227
3228 mptscsih_remove(pdev);
3229 return error;
3230}
3231
3232static void __devexit mptsas_remove(struct pci_dev *pdev)
3233{
3234 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3235 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003236 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237
Eric Mooreb506ade2007-01-29 09:45:37 -07003238 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003239 sas_remove_host(ioc->sh);
3240
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003241 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003242 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3243 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003244 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303245 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003246 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003247 kfree(p);
3248 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003249 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003250
3251 mptscsih_remove(pdev);
3252}
3253
3254static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003255 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003256 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003257 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003258 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003259 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003260 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003261 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003262 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003263 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003264 PCI_ANY_ID, PCI_ANY_ID },
3265 {0} /* Terminating entry */
3266};
3267MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3268
3269
3270static struct pci_driver mptsas_driver = {
3271 .name = "mptsas",
3272 .id_table = mptsas_pci_table,
3273 .probe = mptsas_probe,
3274 .remove = __devexit_p(mptsas_remove),
3275 .shutdown = mptscsih_shutdown,
3276#ifdef CONFIG_PM
3277 .suspend = mptscsih_suspend,
3278 .resume = mptscsih_resume,
3279#endif
3280};
3281
3282static int __init
3283mptsas_init(void)
3284{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303285 int error;
3286
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003287 show_mptmod_ver(my_NAME, my_VERSION);
3288
3289 mptsas_transport_template =
3290 sas_attach_transport(&mptsas_transport_functions);
3291 if (!mptsas_transport_template)
3292 return -ENODEV;
3293
3294 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003295 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003296 mptsasInternalCtx =
3297 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003298 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003299
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303300 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3301 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003302
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303303 error = pci_register_driver(&mptsas_driver);
3304 if (error)
3305 sas_release_transport(mptsas_transport_template);
3306
3307 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003308}
3309
3310static void __exit
3311mptsas_exit(void)
3312{
3313 pci_unregister_driver(&mptsas_driver);
3314 sas_release_transport(mptsas_transport_template);
3315
3316 mpt_reset_deregister(mptsasDoneCtx);
3317 mpt_event_deregister(mptsasDoneCtx);
3318
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003319 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003320 mpt_deregister(mptsasInternalCtx);
3321 mpt_deregister(mptsasTaskCtx);
3322 mpt_deregister(mptsasDoneCtx);
3323}
3324
3325module_init(mptsas_init);
3326module_exit(mptsas_exit);