blob: 1d2d03f77894c75d8b42225da9529479173706c0 [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 Moore07c861d2007-01-29 09:48:50 -07007 * (mailto:mpt_linux_developer@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
Eric Moore547f9a22006-06-27 14:42:12 -0600204#ifdef MPT_DEBUG_SAS
Christoph Hellwigb5141122005-10-28 22:07:41 +0200205static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
206{
207 printk("---- IO UNIT PAGE 0 ------------\n");
208 printk("Handle=0x%X\n",
209 le16_to_cpu(phy_data->AttachedDeviceHandle));
210 printk("Controller Handle=0x%X\n",
211 le16_to_cpu(phy_data->ControllerDevHandle));
212 printk("Port=0x%X\n", phy_data->Port);
213 printk("Port Flags=0x%X\n", phy_data->PortFlags);
214 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
215 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
216 printk("Controller PHY Device Info=0x%X\n",
217 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
218 printk("DiscoveryStatus=0x%X\n",
219 le32_to_cpu(phy_data->DiscoveryStatus));
220 printk("\n");
221}
222
223static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
224{
225 __le64 sas_address;
226
227 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
228
229 printk("---- SAS PHY PAGE 0 ------------\n");
230 printk("Attached Device Handle=0x%X\n",
231 le16_to_cpu(pg0->AttachedDevHandle));
232 printk("SAS Address=0x%llX\n",
233 (unsigned long long)le64_to_cpu(sas_address));
234 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
235 printk("Attached Device Info=0x%X\n",
236 le32_to_cpu(pg0->AttachedDeviceInfo));
237 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
238 printk("Change Count=0x%X\n", pg0->ChangeCount);
239 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
240 printk("\n");
241}
242
243static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
244{
245 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200246 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
247 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200249 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
250 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
251 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252}
253
254static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
255{
256 __le64 sas_address;
257
258 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
259
260 printk("---- SAS DEVICE PAGE 0 ---------\n");
261 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100262 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200263 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
264 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
Eric Mooref99be432007-01-04 20:46:54 -0700265 printk("SAS Address=0x%llX\n", (unsigned long long)
266 le64_to_cpu(sas_address));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200267 printk("Target ID=0x%X\n", pg0->TargetID);
268 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200269 /* The PhyNum field specifies the PHY number of the parent
270 * device this device is linked to
271 */
272 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
273 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200274 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
275 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
276 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
277 printk("\n");
278}
279
280static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
281{
282 printk("---- SAS EXPANDER PAGE 1 ------------\n");
283
284 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200285 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200286 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
287 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
288 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
289 printk("Owner Device Handle=0x%X\n",
290 le16_to_cpu(pg1->OwnerDevHandle));
291 printk("Attached Device Handle=0x%X\n",
292 le16_to_cpu(pg1->AttachedDevHandle));
293}
294#else
295#define mptsas_print_phy_data(phy_data) do { } while (0)
296#define mptsas_print_phy_pg0(pg0) do { } while (0)
297#define mptsas_print_phy_pg1(pg1) do { } while (0)
298#define mptsas_print_device_pg0(pg0) do { } while (0)
299#define mptsas_print_expander_pg1(pg1) do { } while (0)
300#endif
301
Christoph Hellwige3094442006-02-16 13:25:36 +0100302static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
303{
304 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
305 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
306}
307
308static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
309{
310 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
311 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
312}
313
Moore, Erice6b2d762006-03-14 09:14:24 -0700314/*
315 * mptsas_find_portinfo_by_handle
316 *
317 * This function should be called with the sas_topology_mutex already held
318 */
319static struct mptsas_portinfo *
320mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
321{
322 struct mptsas_portinfo *port_info, *rc=NULL;
323 int i;
324
325 list_for_each_entry(port_info, &ioc->sas_topology, list)
326 for (i = 0; i < port_info->num_phys; i++)
327 if (port_info->phy_info[i].identify.handle == handle) {
328 rc = port_info;
329 goto out;
330 }
331 out:
332 return rc;
333}
334
Moore, Ericbd23e942006-04-17 12:43:04 -0600335/*
336 * Returns true if there is a scsi end device
337 */
338static inline int
339mptsas_is_end_device(struct mptsas_devinfo * attached)
340{
Eric Moore547f9a22006-06-27 14:42:12 -0600341 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600342 (attached->device_info &
343 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
344 ((attached->device_info &
345 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
346 (attached->device_info &
347 MPI_SAS_DEVICE_INFO_STP_TARGET) |
348 (attached->device_info &
349 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
350 return 1;
351 else
352 return 0;
353}
354
Eric Moore547f9a22006-06-27 14:42:12 -0600355/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600356static void
Eric Moore547f9a22006-06-27 14:42:12 -0600357mptsas_port_delete(struct mptsas_portinfo_details * port_details)
358{
359 struct mptsas_portinfo *port_info;
360 struct mptsas_phyinfo *phy_info;
361 u8 i;
362
363 if (!port_details)
364 return;
365
366 port_info = port_details->port_info;
367 phy_info = port_info->phy_info;
368
Eric Mooredc22f162006-07-06 11:23:14 -0600369 dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700370 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
371 port_details->num_phys, (unsigned long long)
372 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600373
374 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
375 if(phy_info->port_details != port_details)
376 continue;
377 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
378 phy_info->port_details = NULL;
379 }
380 kfree(port_details);
381}
382
383static inline struct sas_rphy *
384mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
385{
386 if (phy_info->port_details)
387 return phy_info->port_details->rphy;
388 else
389 return NULL;
390}
391
392static inline void
393mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
394{
395 if (phy_info->port_details) {
396 phy_info->port_details->rphy = rphy;
397 dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
398 }
399
400#ifdef MPT_DEBUG_SAS_WIDE
401 if (rphy) {
402 dev_printk(KERN_DEBUG, &rphy->dev, "add:");
403 printk("rphy=%p release=%p\n",
404 rphy, rphy->dev.release);
405 }
406#endif
407}
408
409static inline struct sas_port *
410mptsas_get_port(struct mptsas_phyinfo *phy_info)
411{
412 if (phy_info->port_details)
413 return phy_info->port_details->port;
414 else
415 return NULL;
416}
417
418static inline void
419mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
420{
421 if (phy_info->port_details)
422 phy_info->port_details->port = port;
423
424#ifdef MPT_DEBUG_SAS_WIDE
425 if (port) {
426 dev_printk(KERN_DEBUG, &port->dev, "add: ");
427 printk("port=%p release=%p\n",
428 port, port->dev.release);
429 }
430#endif
431}
432
433static inline struct scsi_target *
434mptsas_get_starget(struct mptsas_phyinfo *phy_info)
435{
436 if (phy_info->port_details)
437 return phy_info->port_details->starget;
438 else
439 return NULL;
440}
441
442static inline void
443mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
444starget)
445{
446 if (phy_info->port_details)
447 phy_info->port_details->starget = starget;
448}
449
450
451/*
452 * mptsas_setup_wide_ports
453 *
454 * Updates for new and existing narrow/wide port configuration
455 * in the sas_topology
456 */
Eric Moore376ac832006-06-29 17:36:26 -0600457static void
Eric Moore547f9a22006-06-27 14:42:12 -0600458mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
459{
460 struct mptsas_portinfo_details * port_details;
461 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
462 u64 sas_address;
463 int i, j;
464
465 mutex_lock(&ioc->sas_topology_mutex);
466
467 phy_info = port_info->phy_info;
468 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
469 if (phy_info->attached.handle)
470 continue;
471 port_details = phy_info->port_details;
472 if (!port_details)
473 continue;
474 if (port_details->num_phys < 2)
475 continue;
476 /*
477 * Removing a phy from a port, letting the last
478 * phy be removed by firmware events.
479 */
480 dsaswideprintk((KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600481 "%s: [%p]: deleting phy = %d\n",
482 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600483 port_details->num_phys--;
484 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
485 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
486 sas_port_delete_phy(port_details->port, phy_info->phy);
487 phy_info->port_details = NULL;
488 }
489
490 /*
491 * Populate and refresh the tree
492 */
493 phy_info = port_info->phy_info;
494 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
495 sas_address = phy_info->attached.sas_address;
496 dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700497 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600498 if (!sas_address)
499 continue;
500 port_details = phy_info->port_details;
501 /*
502 * Forming a port
503 */
504 if (!port_details) {
505 port_details = kzalloc(sizeof(*port_details),
506 GFP_KERNEL);
507 if (!port_details)
508 goto out;
509 port_details->num_phys = 1;
510 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600511 if (phy_info->phy_id < 64 )
512 port_details->phy_bitmask |=
513 (1 << phy_info->phy_id);
514 phy_info->sas_port_add_phy=1;
515 dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700516 "phy_id=%d sas_address=0x%018llX\n",
517 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600518 phy_info->port_details = port_details;
519 }
520
521 if (i == port_info->num_phys - 1)
522 continue;
523 phy_info_cmp = &port_info->phy_info[i + 1];
524 for (j = i + 1 ; j < port_info->num_phys ; j++,
525 phy_info_cmp++) {
526 if (!phy_info_cmp->attached.sas_address)
527 continue;
528 if (sas_address != phy_info_cmp->attached.sas_address)
529 continue;
530 if (phy_info_cmp->port_details == port_details )
531 continue;
532 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700533 "\t\tphy_id=%d sas_address=0x%018llX\n",
534 j, (unsigned long long)
535 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600536 if (phy_info_cmp->port_details) {
537 port_details->rphy =
538 mptsas_get_rphy(phy_info_cmp);
539 port_details->port =
540 mptsas_get_port(phy_info_cmp);
541 port_details->starget =
542 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600543 port_details->num_phys =
544 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600545 if (!phy_info_cmp->port_details->num_phys)
546 kfree(phy_info_cmp->port_details);
547 } else
548 phy_info_cmp->sas_port_add_phy=1;
549 /*
550 * Adding a phy to a port
551 */
552 phy_info_cmp->port_details = port_details;
553 if (phy_info_cmp->phy_id < 64 )
554 port_details->phy_bitmask |=
555 (1 << phy_info_cmp->phy_id);
556 port_details->num_phys++;
557 }
558 }
559
560 out:
561
562#ifdef MPT_DEBUG_SAS_WIDE
563 for (i = 0; i < port_info->num_phys; i++) {
564 port_details = port_info->phy_info[i].port_details;
565 if (!port_details)
566 continue;
567 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700568 "%s: [%p]: phy_id=%02d num_phys=%02d "
569 "bitmask=0x%016llX\n", __FUNCTION__,
570 port_details, i, port_details->num_phys,
571 (unsigned long long)port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600572 dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
573 port_details->port, port_details->rphy));
574 }
575 dsaswideprintk((KERN_DEBUG"\n"));
576#endif
577 mutex_unlock(&ioc->sas_topology_mutex);
578}
579
Eric Mooredf9e0622007-01-29 09:46:21 -0700580/**
581 * csmisas_find_vtarget
582 *
583 * @ioc
584 * @volume_id
585 * @volume_bus
586 *
587 **/
588static VirtTarget *
589mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600590{
Eric Mooredf9e0622007-01-29 09:46:21 -0700591 struct scsi_device *sdev;
592 VirtDevice *vdev;
593 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600594
Eric Mooredf9e0622007-01-29 09:46:21 -0700595 shost_for_each_device(sdev, ioc->sh) {
596 if ((vdev = sdev->hostdata) == NULL)
597 continue;
598 if (vdev->vtarget->id == id &&
599 vdev->vtarget->channel == channel)
600 vtarget = vdev->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600601 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700602 return vtarget;
603}
604
605/**
606 * mptsas_target_reset
607 *
608 * Issues TARGET_RESET to end device using handshaking method
609 *
610 * @ioc
611 * @channel
612 * @id
613 *
614 * Returns (1) success
615 * (0) failure
616 *
617 **/
618static int
619mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
620{
621 MPT_FRAME_HDR *mf;
622 SCSITaskMgmt_t *pScsiTm;
623
624 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
625 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
626 ioc->name,__FUNCTION__, __LINE__));
627 return 0;
628 }
629
630 /* Format the Request
631 */
632 pScsiTm = (SCSITaskMgmt_t *) mf;
633 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
634 pScsiTm->TargetID = id;
635 pScsiTm->Bus = channel;
636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
637 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
638 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
639
640 DBG_DUMP_TM_REQUEST_FRAME(mf);
641
642 if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
643 sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
644 mpt_free_msg_frame(ioc, mf);
645 dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
646 ioc->name,__FUNCTION__, __LINE__));
647 return 0;
648 }
649
650 return 1;
651}
652
653/**
654 * mptsas_target_reset_queue
655 *
656 * Receive request for TARGET_RESET after recieving an firmware
657 * event NOT_RESPONDING_EVENT, then put command in link list
658 * and queue if task_queue already in use.
659 *
660 * @ioc
661 * @sas_event_data
662 *
663 **/
664static void
665mptsas_target_reset_queue(MPT_ADAPTER *ioc,
666 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
667{
668 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
669 VirtTarget *vtarget = NULL;
670 struct mptsas_target_reset_event *target_reset_list;
671 u8 id, channel;
672
673 id = sas_event_data->TargetID;
674 channel = sas_event_data->Bus;
675
676 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
677 return;
678
679 vtarget->deleted = 1; /* block IO */
680
681 target_reset_list = kzalloc(sizeof(*target_reset_list),
682 GFP_ATOMIC);
683 if (!target_reset_list) {
684 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
685 ioc->name,__FUNCTION__, __LINE__));
686 return;
687 }
688
689 memcpy(&target_reset_list->sas_event_data, sas_event_data,
690 sizeof(*sas_event_data));
691 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
692
693 if (hd->resetPending)
694 return;
695
696 if (mptsas_target_reset(ioc, channel, id)) {
697 target_reset_list->target_reset_issued = 1;
698 hd->resetPending = 1;
699 }
700}
701
702/**
703 * mptsas_dev_reset_complete
704 *
705 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
706 * enable work queue to finish off removing device from upper layers.
707 * then send next TARGET_RESET in the queue.
708 *
709 * @ioc
710 *
711 **/
712static void
713mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
714{
715 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
716 struct list_head *head = &hd->target_reset_list;
717 struct mptsas_target_reset_event *target_reset_list;
718 struct mptsas_hotplug_event *ev;
719 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
720 u8 id, channel;
721 __le64 sas_address;
722
723 if (list_empty(head))
724 return;
725
726 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
727
728 sas_event_data = &target_reset_list->sas_event_data;
729 id = sas_event_data->TargetID;
730 channel = sas_event_data->Bus;
731 hd->resetPending = 0;
732
733 /*
734 * retry target reset
735 */
736 if (!target_reset_list->target_reset_issued) {
737 if (mptsas_target_reset(ioc, channel, id)) {
738 target_reset_list->target_reset_issued = 1;
739 hd->resetPending = 1;
740 }
741 return;
742 }
743
744 /*
745 * enable work queue to remove device from upper layers
746 */
747 list_del(&target_reset_list->list);
748
749 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
750 if (!ev) {
751 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
752 ioc->name,__FUNCTION__, __LINE__));
753 return;
754 }
755
756 INIT_WORK(&ev->work, mptsas_hotplug_work);
757 ev->ioc = ioc;
758 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
759 ev->parent_handle =
760 le16_to_cpu(sas_event_data->ParentDevHandle);
761 ev->channel = channel;
762 ev->id =id;
763 ev->phy_id = sas_event_data->PhyNum;
764 memcpy(&sas_address, &sas_event_data->SASAddress,
765 sizeof(__le64));
766 ev->sas_address = le64_to_cpu(sas_address);
767 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
768 ev->event_type = MPTSAS_DEL_DEVICE;
769 schedule_work(&ev->work);
770 kfree(target_reset_list);
771
772 /*
773 * issue target reset to next device in the queue
774 */
775
776 head = &hd->target_reset_list;
777 if (list_empty(head))
778 return;
779
780 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
781 list);
782
783 sas_event_data = &target_reset_list->sas_event_data;
784 id = sas_event_data->TargetID;
785 channel = sas_event_data->Bus;
786
787 if (mptsas_target_reset(ioc, channel, id)) {
788 target_reset_list->target_reset_issued = 1;
789 hd->resetPending = 1;
790 }
791}
792
793/**
794 * mptsas_taskmgmt_complete
795 *
796 * @ioc
797 * @mf
798 * @mr
799 *
800 **/
801static int
802mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
803{
804 mptsas_dev_reset_complete(ioc);
805 return mptscsih_taskmgmt_complete(ioc, mf, mr);
806}
807
808/**
809 * mptscsih_ioc_reset
810 *
811 * @ioc
812 * @reset_phase
813 *
814 **/
815static int
816mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
817{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800818 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700819 struct mptsas_target_reset_event *target_reset_list, *n;
820 int rc;
821
822 rc = mptscsih_ioc_reset(ioc, reset_phase);
823
824 if (ioc->bus_type != SAS)
825 goto out;
826
827 if (reset_phase != MPT_IOC_POST_RESET)
828 goto out;
829
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800830 if (!ioc->sh || !ioc->sh->hostdata)
831 goto out;
832 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
833 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700834 goto out;
835
836 if (list_empty(&hd->target_reset_list))
837 goto out;
838
839 /* flush the target_reset_list */
840 list_for_each_entry_safe(target_reset_list, n,
841 &hd->target_reset_list, list) {
842 list_del(&target_reset_list->list);
843 kfree(target_reset_list);
844 }
845
846 out:
847 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600848}
849
Christoph Hellwige3094442006-02-16 13:25:36 +0100850static int
Moore, Eric52435432006-03-14 09:14:15 -0700851mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100852 u32 form, u32 form_specific)
853{
854 ConfigExtendedPageHeader_t hdr;
855 CONFIGPARMS cfg;
856 SasEnclosurePage0_t *buffer;
857 dma_addr_t dma_handle;
858 int error;
859 __le64 le_identifier;
860
861 memset(&hdr, 0, sizeof(hdr));
862 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
863 hdr.PageNumber = 0;
864 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
865 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
866
867 cfg.cfghdr.ehdr = &hdr;
868 cfg.physAddr = -1;
869 cfg.pageAddr = form + form_specific;
870 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
871 cfg.dir = 0; /* read */
872 cfg.timeout = 10;
873
874 error = mpt_config(ioc, &cfg);
875 if (error)
876 goto out;
877 if (!hdr.ExtPageLength) {
878 error = -ENXIO;
879 goto out;
880 }
881
882 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
883 &dma_handle);
884 if (!buffer) {
885 error = -ENOMEM;
886 goto out;
887 }
888
889 cfg.physAddr = dma_handle;
890 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
891
892 error = mpt_config(ioc, &cfg);
893 if (error)
894 goto out_free_consistent;
895
896 /* save config data */
897 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
898 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
899 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
900 enclosure->flags = le16_to_cpu(buffer->Flags);
901 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
902 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
903 enclosure->start_id = buffer->StartTargetID;
904 enclosure->start_channel = buffer->StartBus;
905 enclosure->sep_id = buffer->SEPTargetID;
906 enclosure->sep_channel = buffer->SEPBus;
907
908 out_free_consistent:
909 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
910 buffer, dma_handle);
911 out:
912 return error;
913}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200914
James Bottomleyf013db32006-03-18 14:54:36 -0600915static int
916mptsas_slave_configure(struct scsi_device *sdev)
917{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600918
James Bottomleye8bf3942006-07-11 17:49:34 -0400919 if (sdev->channel == MPTSAS_RAID_CHANNEL)
920 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600921
James Bottomleye8bf3942006-07-11 17:49:34 -0400922 sas_read_port_mode_page(sdev);
923
924 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600925 return mptscsih_slave_configure(sdev);
926}
927
Eric Moore547f9a22006-06-27 14:42:12 -0600928static int
929mptsas_target_alloc(struct scsi_target *starget)
930{
931 struct Scsi_Host *host = dev_to_shost(&starget->dev);
932 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
933 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700934 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600935 struct sas_rphy *rphy;
936 struct mptsas_portinfo *p;
937 int i;
938
939 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
940 if (!vtarget)
941 return -ENOMEM;
942
943 vtarget->starget = starget;
944 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700945 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
946 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600947 channel = 0;
948
Eric Moore793955f2007-01-29 09:42:20 -0700949 /*
950 * RAID volumes placed beyond the last expected port.
951 */
952 if (starget->channel == MPTSAS_RAID_CHANNEL) {
953 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
954 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
955 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600956 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700957 }
Eric Moore547f9a22006-06-27 14:42:12 -0600958
959 rphy = dev_to_rphy(starget->dev.parent);
960 mutex_lock(&hd->ioc->sas_topology_mutex);
961 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
962 for (i = 0; i < p->num_phys; i++) {
963 if (p->phy_info[i].attached.sas_address !=
964 rphy->identify.sas_address)
965 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700966 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600967 channel = p->phy_info[i].attached.channel;
968 mptsas_set_starget(&p->phy_info[i], starget);
969
970 /*
971 * Exposing hidden raid components
972 */
Eric Moore793955f2007-01-29 09:42:20 -0700973 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
974 id = mptscsih_raid_id_to_num(hd->ioc,
975 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600976 vtarget->tflags |=
977 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700978 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600979 }
980 mutex_unlock(&hd->ioc->sas_topology_mutex);
981 goto out;
982 }
983 }
984 mutex_unlock(&hd->ioc->sas_topology_mutex);
985
986 kfree(vtarget);
987 return -ENXIO;
988
989 out:
Eric Moore793955f2007-01-29 09:42:20 -0700990 vtarget->id = id;
991 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600992 starget->hostdata = vtarget;
993 return 0;
994}
995
996static void
997mptsas_target_destroy(struct scsi_target *starget)
998{
999 struct Scsi_Host *host = dev_to_shost(&starget->dev);
1000 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1001 struct sas_rphy *rphy;
1002 struct mptsas_portinfo *p;
1003 int i;
1004
1005 if (!starget->hostdata)
1006 return;
1007
James Bottomleye8bf3942006-07-11 17:49:34 -04001008 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001009 goto out;
1010
1011 rphy = dev_to_rphy(starget->dev.parent);
1012 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1013 for (i = 0; i < p->num_phys; i++) {
1014 if (p->phy_info[i].attached.sas_address !=
1015 rphy->identify.sas_address)
1016 continue;
1017 mptsas_set_starget(&p->phy_info[i], NULL);
1018 goto out;
1019 }
1020 }
1021
1022 out:
1023 kfree(starget->hostdata);
1024 starget->hostdata = NULL;
1025}
1026
1027
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001028static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001029mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001030{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001031 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001032 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1033 struct sas_rphy *rphy;
1034 struct mptsas_portinfo *p;
1035 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001036 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001037 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001038
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001039 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001040 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -06001041 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001042 hd->ioc->name, sizeof(VirtDevice));
1043 return -ENOMEM;
1044 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001045 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -06001046 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001047
James Bottomleye8bf3942006-07-11 17:49:34 -04001048 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001049 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001050
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001051 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001052 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001053 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1054 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001055 if (p->phy_info[i].attached.sas_address !=
1056 rphy->identify.sas_address)
1057 continue;
1058 vdev->lun = sdev->lun;
1059 /*
1060 * Exposing hidden raid components
1061 */
1062 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001063 p->phy_info[i].attached.channel,
1064 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001065 sdev->no_uld_attach = 1;
1066 mutex_unlock(&hd->ioc->sas_topology_mutex);
1067 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001068 }
1069 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001070 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001071
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001072 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001073 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001074
1075 out:
Eric Moore547f9a22006-06-27 14:42:12 -06001076 vdev->vtarget->num_luns++;
1077 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001078 return 0;
1079}
1080
Eric Moore547f9a22006-06-27 14:42:12 -06001081static int
1082mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001083{
Eric Moore547f9a22006-06-27 14:42:12 -06001084 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001085
Eric Moore793955f2007-01-29 09:42:20 -07001086 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001087 SCpnt->result = DID_NO_CONNECT << 16;
1088 done(SCpnt);
1089 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001090 }
Eric Moore547f9a22006-06-27 14:42:12 -06001091
Eric Moore793955f2007-01-29 09:42:20 -07001092// scsi_print_command(SCpnt);
1093
Eric Moore547f9a22006-06-27 14:42:12 -06001094 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001095}
1096
Eric Moore547f9a22006-06-27 14:42:12 -06001097
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001098static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001099 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001100 .proc_name = "mptsas",
1101 .proc_info = mptscsih_proc_info,
1102 .name = "MPT SPI Host",
1103 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001104 .queuecommand = mptsas_qcmd,
1105 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001106 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001107 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001108 .target_destroy = mptsas_target_destroy,
1109 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001110 .change_queue_depth = mptscsih_change_queue_depth,
1111 .eh_abort_handler = mptscsih_abort,
1112 .eh_device_reset_handler = mptscsih_dev_reset,
1113 .eh_bus_reset_handler = mptscsih_bus_reset,
1114 .eh_host_reset_handler = mptscsih_host_reset,
1115 .bios_param = mptscsih_bios_param,
1116 .can_queue = MPT_FC_CAN_QUEUE,
1117 .this_id = -1,
1118 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1119 .max_sectors = 8192,
1120 .cmd_per_lun = 7,
1121 .use_clustering = ENABLE_CLUSTERING,
1122};
1123
Christoph Hellwigb5141122005-10-28 22:07:41 +02001124static int mptsas_get_linkerrors(struct sas_phy *phy)
1125{
1126 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1127 ConfigExtendedPageHeader_t hdr;
1128 CONFIGPARMS cfg;
1129 SasPhyPage1_t *buffer;
1130 dma_addr_t dma_handle;
1131 int error;
1132
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001133 /* FIXME: only have link errors on local phys */
1134 if (!scsi_is_sas_phy_local(phy))
1135 return -EINVAL;
1136
Christoph Hellwigb5141122005-10-28 22:07:41 +02001137 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1138 hdr.ExtPageLength = 0;
1139 hdr.PageNumber = 1 /* page number 1*/;
1140 hdr.Reserved1 = 0;
1141 hdr.Reserved2 = 0;
1142 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1143 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1144
1145 cfg.cfghdr.ehdr = &hdr;
1146 cfg.physAddr = -1;
1147 cfg.pageAddr = phy->identify.phy_identifier;
1148 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1149 cfg.dir = 0; /* read */
1150 cfg.timeout = 10;
1151
1152 error = mpt_config(ioc, &cfg);
1153 if (error)
1154 return error;
1155 if (!hdr.ExtPageLength)
1156 return -ENXIO;
1157
1158 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1159 &dma_handle);
1160 if (!buffer)
1161 return -ENOMEM;
1162
1163 cfg.physAddr = dma_handle;
1164 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1165
1166 error = mpt_config(ioc, &cfg);
1167 if (error)
1168 goto out_free_consistent;
1169
1170 mptsas_print_phy_pg1(buffer);
1171
1172 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1173 phy->running_disparity_error_count =
1174 le32_to_cpu(buffer->RunningDisparityErrorCount);
1175 phy->loss_of_dword_sync_count =
1176 le32_to_cpu(buffer->LossDwordSynchCount);
1177 phy->phy_reset_problem_count =
1178 le32_to_cpu(buffer->PhyResetProblemCount);
1179
1180 out_free_consistent:
1181 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1182 buffer, dma_handle);
1183 return error;
1184}
1185
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001186static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1187 MPT_FRAME_HDR *reply)
1188{
1189 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1190 if (reply != NULL) {
1191 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1192 memcpy(ioc->sas_mgmt.reply, reply,
1193 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1194 }
1195 complete(&ioc->sas_mgmt.done);
1196 return 1;
1197}
1198
1199static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1200{
1201 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1202 SasIoUnitControlRequest_t *req;
1203 SasIoUnitControlReply_t *reply;
1204 MPT_FRAME_HDR *mf;
1205 MPIHeader_t *hdr;
1206 unsigned long timeleft;
1207 int error = -ERESTARTSYS;
1208
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001209 /* FIXME: fusion doesn't allow non-local phy reset */
1210 if (!scsi_is_sas_phy_local(phy))
1211 return -EINVAL;
1212
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001213 /* not implemented for expanders */
1214 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1215 return -ENXIO;
1216
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001217 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001218 goto out;
1219
1220 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1221 if (!mf) {
1222 error = -ENOMEM;
1223 goto out_unlock;
1224 }
1225
1226 hdr = (MPIHeader_t *) mf;
1227 req = (SasIoUnitControlRequest_t *)mf;
1228 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1229 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1230 req->MsgContext = hdr->MsgContext;
1231 req->Operation = hard_reset ?
1232 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1233 req->PhyNum = phy->identify.phy_identifier;
1234
1235 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1236
1237 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1238 10 * HZ);
1239 if (!timeleft) {
1240 /* On timeout reset the board */
1241 mpt_free_msg_frame(ioc, mf);
1242 mpt_HardResetHandler(ioc, CAN_SLEEP);
1243 error = -ETIMEDOUT;
1244 goto out_unlock;
1245 }
1246
1247 /* a reply frame is expected */
1248 if ((ioc->sas_mgmt.status &
1249 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1250 error = -ENXIO;
1251 goto out_unlock;
1252 }
1253
1254 /* process the completed Reply Message Frame */
1255 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1256 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1257 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1258 __FUNCTION__,
1259 reply->IOCStatus,
1260 reply->IOCLogInfo);
1261 error = -ENXIO;
1262 goto out_unlock;
1263 }
1264
1265 error = 0;
1266
1267 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001268 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001269 out:
1270 return error;
1271}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001272
Christoph Hellwige3094442006-02-16 13:25:36 +01001273static int
1274mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1275{
1276 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1277 int i, error;
1278 struct mptsas_portinfo *p;
1279 struct mptsas_enclosure enclosure_info;
1280 u64 enclosure_handle;
1281
1282 mutex_lock(&ioc->sas_topology_mutex);
1283 list_for_each_entry(p, &ioc->sas_topology, list) {
1284 for (i = 0; i < p->num_phys; i++) {
1285 if (p->phy_info[i].attached.sas_address ==
1286 rphy->identify.sas_address) {
1287 enclosure_handle = p->phy_info[i].
1288 attached.handle_enclosure;
1289 goto found_info;
1290 }
1291 }
1292 }
1293 mutex_unlock(&ioc->sas_topology_mutex);
1294 return -ENXIO;
1295
1296 found_info:
1297 mutex_unlock(&ioc->sas_topology_mutex);
1298 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001299 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001300 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1301 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1302 if (!error)
1303 *identifier = enclosure_info.enclosure_logical_id;
1304 return error;
1305}
1306
1307static int
1308mptsas_get_bay_identifier(struct sas_rphy *rphy)
1309{
1310 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1311 struct mptsas_portinfo *p;
1312 int i, rc;
1313
1314 mutex_lock(&ioc->sas_topology_mutex);
1315 list_for_each_entry(p, &ioc->sas_topology, list) {
1316 for (i = 0; i < p->num_phys; i++) {
1317 if (p->phy_info[i].attached.sas_address ==
1318 rphy->identify.sas_address) {
1319 rc = p->phy_info[i].attached.slot;
1320 goto out;
1321 }
1322 }
1323 }
1324 rc = -ENXIO;
1325 out:
1326 mutex_unlock(&ioc->sas_topology_mutex);
1327 return rc;
1328}
1329
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001330static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001331 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001332 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1333 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001334 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001335};
1336
1337static struct scsi_transport_template *mptsas_transport_template;
1338
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001339static int
1340mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1341{
1342 ConfigExtendedPageHeader_t hdr;
1343 CONFIGPARMS cfg;
1344 SasIOUnitPage0_t *buffer;
1345 dma_addr_t dma_handle;
1346 int error, i;
1347
1348 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1349 hdr.ExtPageLength = 0;
1350 hdr.PageNumber = 0;
1351 hdr.Reserved1 = 0;
1352 hdr.Reserved2 = 0;
1353 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1354 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1355
1356 cfg.cfghdr.ehdr = &hdr;
1357 cfg.physAddr = -1;
1358 cfg.pageAddr = 0;
1359 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1360 cfg.dir = 0; /* read */
1361 cfg.timeout = 10;
1362
1363 error = mpt_config(ioc, &cfg);
1364 if (error)
1365 goto out;
1366 if (!hdr.ExtPageLength) {
1367 error = -ENXIO;
1368 goto out;
1369 }
1370
1371 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1372 &dma_handle);
1373 if (!buffer) {
1374 error = -ENOMEM;
1375 goto out;
1376 }
1377
1378 cfg.physAddr = dma_handle;
1379 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1380
1381 error = mpt_config(ioc, &cfg);
1382 if (error)
1383 goto out_free_consistent;
1384
1385 port_info->num_phys = buffer->NumPhys;
1386 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001387 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001388 if (!port_info->phy_info) {
1389 error = -ENOMEM;
1390 goto out_free_consistent;
1391 }
1392
1393 for (i = 0; i < port_info->num_phys; i++) {
1394 mptsas_print_phy_data(&buffer->PhyData[i]);
1395 port_info->phy_info[i].phy_id = i;
1396 port_info->phy_info[i].port_id =
1397 buffer->PhyData[i].Port;
1398 port_info->phy_info[i].negotiated_link_rate =
1399 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001400 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001401 port_info->phy_info[i].handle =
1402 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001403 }
1404
1405 out_free_consistent:
1406 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1407 buffer, dma_handle);
1408 out:
1409 return error;
1410}
1411
1412static int
1413mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1414 u32 form, u32 form_specific)
1415{
1416 ConfigExtendedPageHeader_t hdr;
1417 CONFIGPARMS cfg;
1418 SasPhyPage0_t *buffer;
1419 dma_addr_t dma_handle;
1420 int error;
1421
1422 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1423 hdr.ExtPageLength = 0;
1424 hdr.PageNumber = 0;
1425 hdr.Reserved1 = 0;
1426 hdr.Reserved2 = 0;
1427 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1428 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1429
1430 cfg.cfghdr.ehdr = &hdr;
1431 cfg.dir = 0; /* read */
1432 cfg.timeout = 10;
1433
1434 /* Get Phy Pg 0 for each Phy. */
1435 cfg.physAddr = -1;
1436 cfg.pageAddr = form + form_specific;
1437 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1438
1439 error = mpt_config(ioc, &cfg);
1440 if (error)
1441 goto out;
1442
1443 if (!hdr.ExtPageLength) {
1444 error = -ENXIO;
1445 goto out;
1446 }
1447
1448 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1449 &dma_handle);
1450 if (!buffer) {
1451 error = -ENOMEM;
1452 goto out;
1453 }
1454
1455 cfg.physAddr = dma_handle;
1456 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1457
1458 error = mpt_config(ioc, &cfg);
1459 if (error)
1460 goto out_free_consistent;
1461
1462 mptsas_print_phy_pg0(buffer);
1463
1464 phy_info->hw_link_rate = buffer->HwLinkRate;
1465 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1466 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1467 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1468
1469 out_free_consistent:
1470 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1471 buffer, dma_handle);
1472 out:
1473 return error;
1474}
1475
1476static int
1477mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1478 u32 form, u32 form_specific)
1479{
1480 ConfigExtendedPageHeader_t hdr;
1481 CONFIGPARMS cfg;
1482 SasDevicePage0_t *buffer;
1483 dma_addr_t dma_handle;
1484 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001485 int error=0;
1486
1487 if (ioc->sas_discovery_runtime &&
1488 mptsas_is_end_device(device_info))
1489 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001490
1491 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1492 hdr.ExtPageLength = 0;
1493 hdr.PageNumber = 0;
1494 hdr.Reserved1 = 0;
1495 hdr.Reserved2 = 0;
1496 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1497 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1498
1499 cfg.cfghdr.ehdr = &hdr;
1500 cfg.pageAddr = form + form_specific;
1501 cfg.physAddr = -1;
1502 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1503 cfg.dir = 0; /* read */
1504 cfg.timeout = 10;
1505
Moore, Ericdb9c9172006-03-14 09:14:18 -07001506 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001507 error = mpt_config(ioc, &cfg);
1508 if (error)
1509 goto out;
1510 if (!hdr.ExtPageLength) {
1511 error = -ENXIO;
1512 goto out;
1513 }
1514
1515 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1516 &dma_handle);
1517 if (!buffer) {
1518 error = -ENOMEM;
1519 goto out;
1520 }
1521
1522 cfg.physAddr = dma_handle;
1523 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1524
1525 error = mpt_config(ioc, &cfg);
1526 if (error)
1527 goto out_free_consistent;
1528
1529 mptsas_print_device_pg0(buffer);
1530
1531 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001532 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001533 device_info->handle_enclosure =
1534 le16_to_cpu(buffer->EnclosureHandle);
1535 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001536 device_info->phy_id = buffer->PhyNum;
1537 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001538 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001539 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001540 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001541 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1542 device_info->sas_address = le64_to_cpu(sas_address);
1543 device_info->device_info =
1544 le32_to_cpu(buffer->DeviceInfo);
1545
1546 out_free_consistent:
1547 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1548 buffer, dma_handle);
1549 out:
1550 return error;
1551}
1552
1553static int
1554mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1555 u32 form, u32 form_specific)
1556{
1557 ConfigExtendedPageHeader_t hdr;
1558 CONFIGPARMS cfg;
1559 SasExpanderPage0_t *buffer;
1560 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001561 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001562
1563 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1564 hdr.ExtPageLength = 0;
1565 hdr.PageNumber = 0;
1566 hdr.Reserved1 = 0;
1567 hdr.Reserved2 = 0;
1568 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1569 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1570
1571 cfg.cfghdr.ehdr = &hdr;
1572 cfg.physAddr = -1;
1573 cfg.pageAddr = form + form_specific;
1574 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1575 cfg.dir = 0; /* read */
1576 cfg.timeout = 10;
1577
Moore, Ericdb9c9172006-03-14 09:14:18 -07001578 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001579 error = mpt_config(ioc, &cfg);
1580 if (error)
1581 goto out;
1582
1583 if (!hdr.ExtPageLength) {
1584 error = -ENXIO;
1585 goto out;
1586 }
1587
1588 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1589 &dma_handle);
1590 if (!buffer) {
1591 error = -ENOMEM;
1592 goto out;
1593 }
1594
1595 cfg.physAddr = dma_handle;
1596 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1597
1598 error = mpt_config(ioc, &cfg);
1599 if (error)
1600 goto out_free_consistent;
1601
1602 /* save config data */
1603 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001604 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001605 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001606 if (!port_info->phy_info) {
1607 error = -ENOMEM;
1608 goto out_free_consistent;
1609 }
1610
Eric Moore2ecce492007-01-29 09:47:08 -07001611 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001612 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001613 port_info->phy_info[i].handle =
1614 le16_to_cpu(buffer->DevHandle);
1615 }
Eric Moore547f9a22006-06-27 14:42:12 -06001616
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001617 out_free_consistent:
1618 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1619 buffer, dma_handle);
1620 out:
1621 return error;
1622}
1623
1624static int
1625mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1626 u32 form, u32 form_specific)
1627{
1628 ConfigExtendedPageHeader_t hdr;
1629 CONFIGPARMS cfg;
1630 SasExpanderPage1_t *buffer;
1631 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001632 int error=0;
1633
1634 if (ioc->sas_discovery_runtime &&
1635 mptsas_is_end_device(&phy_info->attached))
1636 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001637
1638 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1639 hdr.ExtPageLength = 0;
1640 hdr.PageNumber = 1;
1641 hdr.Reserved1 = 0;
1642 hdr.Reserved2 = 0;
1643 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1644 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1645
1646 cfg.cfghdr.ehdr = &hdr;
1647 cfg.physAddr = -1;
1648 cfg.pageAddr = form + form_specific;
1649 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1650 cfg.dir = 0; /* read */
1651 cfg.timeout = 10;
1652
1653 error = mpt_config(ioc, &cfg);
1654 if (error)
1655 goto out;
1656
1657 if (!hdr.ExtPageLength) {
1658 error = -ENXIO;
1659 goto out;
1660 }
1661
1662 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1663 &dma_handle);
1664 if (!buffer) {
1665 error = -ENOMEM;
1666 goto out;
1667 }
1668
1669 cfg.physAddr = dma_handle;
1670 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1671
1672 error = mpt_config(ioc, &cfg);
1673 if (error)
1674 goto out_free_consistent;
1675
1676
1677 mptsas_print_expander_pg1(buffer);
1678
1679 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001680 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001681 phy_info->port_id = buffer->PhysicalPort;
1682 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1683 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1684 phy_info->hw_link_rate = buffer->HwLinkRate;
1685 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1686 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1687
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001688 out_free_consistent:
1689 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1690 buffer, dma_handle);
1691 out:
1692 return error;
1693}
1694
1695static void
1696mptsas_parse_device_info(struct sas_identify *identify,
1697 struct mptsas_devinfo *device_info)
1698{
1699 u16 protocols;
1700
1701 identify->sas_address = device_info->sas_address;
1702 identify->phy_identifier = device_info->phy_id;
1703
1704 /*
1705 * Fill in Phy Initiator Port Protocol.
1706 * Bits 6:3, more than one bit can be set, fall through cases.
1707 */
1708 protocols = device_info->device_info & 0x78;
1709 identify->initiator_port_protocols = 0;
1710 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1711 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1712 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1713 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1714 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1715 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1716 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1717 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1718
1719 /*
1720 * Fill in Phy Target Port Protocol.
1721 * Bits 10:7, more than one bit can be set, fall through cases.
1722 */
1723 protocols = device_info->device_info & 0x780;
1724 identify->target_port_protocols = 0;
1725 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1726 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1727 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1728 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1729 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1730 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1731 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1732 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1733
1734 /*
1735 * Fill in Attached device type.
1736 */
1737 switch (device_info->device_info &
1738 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1739 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1740 identify->device_type = SAS_PHY_UNUSED;
1741 break;
1742 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1743 identify->device_type = SAS_END_DEVICE;
1744 break;
1745 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1746 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1747 break;
1748 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1749 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1750 break;
1751 }
1752}
1753
1754static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001755 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001756{
Moore, Erice6b2d762006-03-14 09:14:24 -07001757 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001758 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001759 struct sas_port *port;
1760 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001761
Eric Moore547f9a22006-06-27 14:42:12 -06001762 if (!dev) {
1763 error = -ENODEV;
1764 goto out;
1765 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001766
1767 if (!phy_info->phy) {
1768 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001769 if (!phy) {
1770 error = -ENOMEM;
1771 goto out;
1772 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001773 } else
1774 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001775
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001776 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001777
1778 /*
1779 * Set Negotiated link rate.
1780 */
1781 switch (phy_info->negotiated_link_rate) {
1782 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001783 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001784 break;
1785 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001786 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001787 break;
1788 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001789 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001790 break;
1791 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001792 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001793 break;
1794 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1795 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1796 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001797 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001798 break;
1799 }
1800
1801 /*
1802 * Set Max hardware link rate.
1803 */
1804 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1805 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001806 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001807 break;
1808 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001809 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001810 break;
1811 default:
1812 break;
1813 }
1814
1815 /*
1816 * Set Max programmed link rate.
1817 */
1818 switch (phy_info->programmed_link_rate &
1819 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1820 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001821 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001822 break;
1823 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001824 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001825 break;
1826 default:
1827 break;
1828 }
1829
1830 /*
1831 * Set Min hardware link rate.
1832 */
1833 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1834 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001835 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001836 break;
1837 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001838 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001839 break;
1840 default:
1841 break;
1842 }
1843
1844 /*
1845 * Set Min programmed link rate.
1846 */
1847 switch (phy_info->programmed_link_rate &
1848 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1849 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001850 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001851 break;
1852 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001853 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854 break;
1855 default:
1856 break;
1857 }
1858
Moore, Erice6b2d762006-03-14 09:14:24 -07001859 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001860
Moore, Erice6b2d762006-03-14 09:14:24 -07001861 error = sas_phy_add(phy);
1862 if (error) {
1863 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001864 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001865 }
1866 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001867 }
1868
Eric Moore547f9a22006-06-27 14:42:12 -06001869 if (!phy_info->attached.handle ||
1870 !phy_info->port_details)
1871 goto out;
1872
1873 port = mptsas_get_port(phy_info);
1874 ioc = phy_to_ioc(phy_info->phy);
1875
1876 if (phy_info->sas_port_add_phy) {
1877
1878 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001879 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001880 if (!port) {
1881 error = -ENOMEM;
1882 goto out;
1883 }
1884 error = sas_port_add(port);
1885 if (error) {
1886 dfailprintk((MYIOC_s_ERR_FMT
1887 "%s: exit at line=%d\n", ioc->name,
1888 __FUNCTION__, __LINE__));
1889 goto out;
1890 }
1891 mptsas_set_port(phy_info, port);
Eric Mooredc22f162006-07-06 11:23:14 -06001892 dsaswideprintk((KERN_DEBUG
1893 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1894 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001895 }
1896 dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
1897 phy_info->phy_id));
1898 sas_port_add_phy(port, phy_info->phy);
1899 phy_info->sas_port_add_phy = 0;
1900 }
1901
1902 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001903
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001904 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001905 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001906 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001907
James Bottomley2686de22006-06-30 12:54:02 -05001908 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001909 /*
1910 * Let the hotplug_work thread handle processing
1911 * the adding/removing of devices that occur
1912 * after start of day.
1913 */
1914 if (ioc->sas_discovery_runtime &&
1915 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001916 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001917
James Bottomleyf013db32006-03-18 14:54:36 -06001918 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001919 if (scsi_is_host_device(parent)) {
1920 struct mptsas_portinfo *port_info;
1921 int i;
1922
1923 mutex_lock(&ioc->sas_topology_mutex);
1924 port_info = mptsas_find_portinfo_by_handle(ioc,
1925 ioc->handle);
1926 mutex_unlock(&ioc->sas_topology_mutex);
1927
1928 for (i = 0; i < port_info->num_phys; i++)
1929 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001930 identify.sas_address) {
1931 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001932 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001933 }
James Bottomley2686de22006-06-30 12:54:02 -05001934
1935 } else if (scsi_is_sas_rphy(parent)) {
1936 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
1937 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001938 parent_rphy->identify.sas_address) {
1939 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001940 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001941 }
James Bottomley2686de22006-06-30 12:54:02 -05001942 }
1943
James Bottomleyf013db32006-03-18 14:54:36 -06001944 switch (identify.device_type) {
1945 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001946 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06001947 break;
1948 case SAS_EDGE_EXPANDER_DEVICE:
1949 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001950 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06001951 break;
1952 default:
1953 rphy = NULL;
1954 break;
1955 }
Eric Moore547f9a22006-06-27 14:42:12 -06001956 if (!rphy) {
1957 dfailprintk((MYIOC_s_ERR_FMT
1958 "%s: exit at line=%d\n", ioc->name,
1959 __FUNCTION__, __LINE__));
1960 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001961 }
1962
Eric Moore547f9a22006-06-27 14:42:12 -06001963 rphy->identify = identify;
1964 error = sas_rphy_add(rphy);
1965 if (error) {
1966 dfailprintk((MYIOC_s_ERR_FMT
1967 "%s: exit at line=%d\n", ioc->name,
1968 __FUNCTION__, __LINE__));
1969 sas_rphy_free(rphy);
1970 goto out;
1971 }
1972 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001973 }
1974
Eric Moore547f9a22006-06-27 14:42:12 -06001975 out:
1976 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001977}
1978
1979static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001980mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001981{
Moore, Erice6b2d762006-03-14 09:14:24 -07001982 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001983 int error = -ENOMEM, i;
1984
Moore, Erice6b2d762006-03-14 09:14:24 -07001985 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1986 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001987 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001988
Moore, Erice6b2d762006-03-14 09:14:24 -07001989 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001990 if (error)
1991 goto out_free_port_info;
1992
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001993 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07001994 ioc->handle = hba->phy_info[0].handle;
1995 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001996 if (!port_info) {
1997 port_info = hba;
1998 list_add_tail(&port_info->list, &ioc->sas_topology);
1999 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002000 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002001 port_info->phy_info[i].negotiated_link_rate =
2002 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002003 port_info->phy_info[i].handle =
2004 hba->phy_info[i].handle;
2005 port_info->phy_info[i].port_id =
2006 hba->phy_info[i].port_id;
2007 }
Eric Moore547f9a22006-06-27 14:42:12 -06002008 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002009 kfree(hba);
2010 hba = NULL;
2011 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002012 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002013 for (i = 0; i < port_info->num_phys; i++) {
2014 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2015 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2016 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2017
2018 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002019 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2020 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2021 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002022 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002023 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002024 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002025 mptsas_sas_device_pg0(ioc,
2026 &port_info->phy_info[i].attached,
2027 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2028 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2029 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002030 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002031
Eric Moore547f9a22006-06-27 14:42:12 -06002032 mptsas_setup_wide_ports(ioc, port_info);
2033
2034 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002035 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002036 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002037
2038 return 0;
2039
2040 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002041 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002042 out:
2043 return error;
2044}
2045
2046static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002047mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002048{
Moore, Erice6b2d762006-03-14 09:14:24 -07002049 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002050 struct device *parent;
2051 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002052 int error = -ENOMEM, i, j;
2053
Moore, Erice6b2d762006-03-14 09:14:24 -07002054 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2055 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002056 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002057
Moore, Erice6b2d762006-03-14 09:14:24 -07002058 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002059 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2060 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002061 if (error)
2062 goto out_free_port_info;
2063
Eric Moore2ecce492007-01-29 09:47:08 -07002064 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002065
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002066 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002067 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2068 if (!port_info) {
2069 port_info = ex;
2070 list_add_tail(&port_info->list, &ioc->sas_topology);
2071 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002072 for (i = 0; i < ex->num_phys; i++) {
2073 port_info->phy_info[i].handle =
2074 ex->phy_info[i].handle;
2075 port_info->phy_info[i].port_id =
2076 ex->phy_info[i].port_id;
2077 }
Eric Moore547f9a22006-06-27 14:42:12 -06002078 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002079 kfree(ex);
2080 ex = NULL;
2081 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002082 mutex_unlock(&ioc->sas_topology_mutex);
2083
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002084 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2086 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2087 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2088
2089 if (port_info->phy_info[i].identify.handle) {
2090 mptsas_sas_device_pg0(ioc,
2091 &port_info->phy_info[i].identify,
2092 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2093 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2094 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002095 port_info->phy_info[i].identify.phy_id =
2096 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002097 }
2098
2099 if (port_info->phy_info[i].attached.handle) {
2100 mptsas_sas_device_pg0(ioc,
2101 &port_info->phy_info[i].attached,
2102 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2103 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2104 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002105 port_info->phy_info[i].attached.phy_id =
2106 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002107 }
Eric Moore547f9a22006-06-27 14:42:12 -06002108 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002109
Eric Moore547f9a22006-06-27 14:42:12 -06002110 parent = &ioc->sh->shost_gendev;
2111 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002112 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002113 list_for_each_entry(p, &ioc->sas_topology, list) {
2114 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002115 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002116 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002117 continue;
2118 rphy = mptsas_get_rphy(&p->phy_info[j]);
2119 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002120 }
2121 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002122 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002123 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002124
Eric Moore547f9a22006-06-27 14:42:12 -06002125 mptsas_setup_wide_ports(ioc, port_info);
2126
2127 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002128 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002129 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002130
2131 return 0;
2132
2133 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002134 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002135 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002136 kfree(ex);
2137 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002138 out:
2139 return error;
2140}
2141
Moore, Erice6b2d762006-03-14 09:14:24 -07002142/*
2143 * mptsas_delete_expander_phys
2144 *
2145 *
2146 * This will traverse topology, and remove expanders
2147 * that are no longer present
2148 */
2149static void
2150mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2151{
2152 struct mptsas_portinfo buffer;
2153 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002154 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002155 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002156 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002157 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002158
2159 mutex_lock(&ioc->sas_topology_mutex);
2160 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2161
2162 if (port_info->phy_info &&
2163 (!(port_info->phy_info[0].identify.device_info &
2164 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2165 continue;
2166
2167 if (mptsas_sas_expander_pg0(ioc, &buffer,
2168 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002169 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2170 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002171
2172 /*
2173 * Obtain the port_info instance to the parent port
2174 */
2175 parent = mptsas_find_portinfo_by_handle(ioc,
2176 port_info->phy_info[0].identify.handle_parent);
2177
2178 if (!parent)
2179 goto next_port;
2180
Eric Moore547f9a22006-06-27 14:42:12 -06002181 expander_sas_address =
2182 port_info->phy_info[0].identify.sas_address;
2183
Moore, Erice6b2d762006-03-14 09:14:24 -07002184 /*
2185 * Delete rphys in the parent that point
2186 * to this expander. The transport layer will
2187 * cleanup all the children.
2188 */
Eric Moore547f9a22006-06-27 14:42:12 -06002189 phy_info = parent->phy_info;
2190 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2191 port = mptsas_get_port(phy_info);
2192 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002193 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002194 if (phy_info->attached.sas_address !=
2195 expander_sas_address)
2196 continue;
2197#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002198 dev_printk(KERN_DEBUG, &port->dev,
2199 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002200#endif
2201 sas_port_delete(port);
2202 mptsas_port_delete(phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002203 }
2204 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002205
2206 phy_info = port_info->phy_info;
2207 for (i = 0; i < port_info->num_phys; i++, phy_info++)
2208 mptsas_port_delete(phy_info->port_details);
2209
Moore, Erice6b2d762006-03-14 09:14:24 -07002210 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002211 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002212 kfree(port_info);
2213 }
2214 /*
2215 * Free this memory allocated from inside
2216 * mptsas_sas_expander_pg0
2217 */
Eric Moore547f9a22006-06-27 14:42:12 -06002218 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002219 }
2220 mutex_unlock(&ioc->sas_topology_mutex);
2221}
2222
2223/*
2224 * Start of day discovery
2225 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002226static void
2227mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2228{
2229 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002230 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002231
Moore, Erice6b2d762006-03-14 09:14:24 -07002232 mutex_lock(&ioc->sas_discovery_mutex);
2233 mptsas_probe_hba_phys(ioc);
2234 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002235 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002236 /*
2237 Reporting RAID volumes.
2238 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002239 if (!ioc->ir_firmware)
2240 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002241 if (!ioc->raid_data.pIocPg2)
2242 goto out;
2243 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2244 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002245 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002246 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002247 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2248 }
2249 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002250 mutex_unlock(&ioc->sas_discovery_mutex);
2251}
2252
2253/*
2254 * Work queue thread to handle Runtime discovery
2255 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002256 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002257 */
2258static void
Eric Moore547f9a22006-06-27 14:42:12 -06002259__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002260{
Moore, Erice6b2d762006-03-14 09:14:24 -07002261 u32 handle = 0xFFFF;
2262
Moore, Erice6b2d762006-03-14 09:14:24 -07002263 ioc->sas_discovery_runtime=1;
2264 mptsas_delete_expander_phys(ioc);
2265 mptsas_probe_hba_phys(ioc);
2266 while (!mptsas_probe_expander_phys(ioc, &handle))
2267 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002268 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002269}
2270
2271/*
2272 * Work queue thread to handle Runtime discovery
2273 * Mere purpose is the hot add/delete of expanders
2274 *(Mutex LOCKED)
2275 */
2276static void
David Howellsc4028952006-11-22 14:57:56 +00002277mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002278{
David Howellsc4028952006-11-22 14:57:56 +00002279 struct mptsas_discovery_event *ev =
2280 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002281 MPT_ADAPTER *ioc = ev->ioc;
2282
2283 mutex_lock(&ioc->sas_discovery_mutex);
2284 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002285 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002286 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002287}
2288
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002289static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002290mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002291{
2292 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002293 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002294 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002295
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002296 mutex_lock(&ioc->sas_topology_mutex);
2297 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2298 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002299 if (!mptsas_is_end_device(
2300 &port_info->phy_info[i].attached))
2301 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002302 if (port_info->phy_info[i].attached.sas_address
2303 != sas_address)
2304 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002305 phy_info = &port_info->phy_info[i];
2306 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002307 }
2308 }
2309 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002310 return phy_info;
2311}
2312
2313static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002314mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002315{
2316 struct mptsas_portinfo *port_info;
2317 struct mptsas_phyinfo *phy_info = NULL;
2318 int i;
2319
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002320 mutex_lock(&ioc->sas_topology_mutex);
2321 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002322 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002323 if (!mptsas_is_end_device(
2324 &port_info->phy_info[i].attached))
2325 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002326 if (port_info->phy_info[i].attached.id != id)
2327 continue;
2328 if (port_info->phy_info[i].attached.channel != channel)
2329 continue;
2330 phy_info = &port_info->phy_info[i];
2331 break;
2332 }
2333 }
2334 mutex_unlock(&ioc->sas_topology_mutex);
2335 return phy_info;
2336}
2337
2338static struct mptsas_phyinfo *
2339mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2340{
2341 struct mptsas_portinfo *port_info;
2342 struct mptsas_phyinfo *phy_info = NULL;
2343 int i;
2344
2345 mutex_lock(&ioc->sas_topology_mutex);
2346 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2347 for (i = 0; i < port_info->num_phys; i++) {
2348 if (!mptsas_is_end_device(
2349 &port_info->phy_info[i].attached))
2350 continue;
2351 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2352 continue;
2353 if (port_info->phy_info[i].attached.phys_disk_num != id)
2354 continue;
2355 if (port_info->phy_info[i].attached.channel != channel)
2356 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002357 phy_info = &port_info->phy_info[i];
2358 break;
2359 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002360 }
2361 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002362 return phy_info;
2363}
2364
Moore, Eric4b766472006-03-14 09:14:12 -07002365/*
2366 * Work queue thread to clear the persitency table
2367 */
2368static void
David Howellsc4028952006-11-22 14:57:56 +00002369mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002370{
David Howellsc4028952006-11-22 14:57:56 +00002371 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002372
2373 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2374}
2375
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002376static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002377mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2378{
Eric Mooref99be432007-01-04 20:46:54 -07002379 int rc;
2380
Moore, Ericf44e5462006-03-14 09:14:21 -07002381 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002382 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002383}
2384
2385static void
2386mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2387{
2388 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2389 mptsas_reprobe_lun);
2390}
2391
Eric Mooreb506ade2007-01-29 09:45:37 -07002392static void
2393mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2394{
2395 CONFIGPARMS cfg;
2396 ConfigPageHeader_t hdr;
2397 dma_addr_t dma_handle;
2398 pRaidVolumePage0_t buffer = NULL;
2399 RaidPhysDiskPage0_t phys_disk;
2400 int i;
2401 struct mptsas_hotplug_event *ev;
2402
2403 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2404 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2405 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2406 cfg.pageAddr = (channel << 8) + id;
2407 cfg.cfghdr.hdr = &hdr;
2408 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2409
2410 if (mpt_config(ioc, &cfg) != 0)
2411 goto out;
2412
2413 if (!hdr.PageLength)
2414 goto out;
2415
2416 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2417 &dma_handle);
2418
2419 if (!buffer)
2420 goto out;
2421
2422 cfg.physAddr = dma_handle;
2423 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2424
2425 if (mpt_config(ioc, &cfg) != 0)
2426 goto out;
2427
2428 if (!(buffer->VolumeStatus.Flags &
2429 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2430 goto out;
2431
2432 if (!buffer->NumPhysDisks)
2433 goto out;
2434
2435 for (i = 0; i < buffer->NumPhysDisks; i++) {
2436
2437 if (mpt_raid_phys_disk_pg0(ioc,
2438 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2439 continue;
2440
2441 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2442 if (!ev) {
2443 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2444 goto out;
2445 }
2446
2447 INIT_WORK(&ev->work, mptsas_hotplug_work);
2448 ev->ioc = ioc;
2449 ev->id = phys_disk.PhysDiskID;
2450 ev->channel = phys_disk.PhysDiskBus;
2451 ev->phys_disk_num_valid = 1;
2452 ev->phys_disk_num = phys_disk.PhysDiskNum;
2453 ev->event_type = MPTSAS_ADD_DEVICE;
2454 schedule_work(&ev->work);
2455 }
2456
2457 out:
2458 if (buffer)
2459 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2460 dma_handle);
2461}
Moore, Erice6b2d762006-03-14 09:14:24 -07002462/*
2463 * Work queue thread to handle SAS hotplug events
2464 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002465static void
David Howellsc4028952006-11-22 14:57:56 +00002466mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002467{
David Howellsc4028952006-11-22 14:57:56 +00002468 struct mptsas_hotplug_event *ev =
2469 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002470
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002471 MPT_ADAPTER *ioc = ev->ioc;
2472 struct mptsas_phyinfo *phy_info;
2473 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002474 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002475 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002476 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002477 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002478 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002479 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002480 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002481 VirtDevice *vdevice;
2482
Moore, Erice6b2d762006-03-14 09:14:24 -07002483 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002484 switch (ev->event_type) {
2485 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002486
Eric Mooreb506ade2007-01-29 09:45:37 -07002487 phy_info = NULL;
2488 if (ev->phys_disk_num_valid) {
2489 if (ev->hidden_raid_component){
2490 if (mptsas_sas_device_pg0(ioc, &sas_device,
2491 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2492 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2493 (ev->channel << 8) + ev->id)) {
2494 dfailprintk((MYIOC_s_ERR_FMT
2495 "%s: exit at line=%d\n", ioc->name,
2496 __FUNCTION__, __LINE__));
2497 break;
2498 }
2499 phy_info = mptsas_find_phyinfo_by_sas_address(
2500 ioc, sas_device.sas_address);
2501 }else
2502 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2503 ioc, ev->channel, ev->phys_disk_num);
2504 }
2505
2506 if (!phy_info)
2507 phy_info = mptsas_find_phyinfo_by_target(ioc,
2508 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002509
Moore, Ericf44e5462006-03-14 09:14:21 -07002510 /*
2511 * Sanity checks, for non-existing phys and remote rphys.
2512 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002513 if (!phy_info){
2514 dfailprintk((MYIOC_s_ERR_FMT
2515 "%s: exit at line=%d\n", ioc->name,
2516 __FUNCTION__, __LINE__));
2517 break;
2518 }
2519 if (!phy_info->port_details) {
Eric Moore547f9a22006-06-27 14:42:12 -06002520 dfailprintk((MYIOC_s_ERR_FMT
2521 "%s: exit at line=%d\n", ioc->name,
2522 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002523 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002524 }
2525 rphy = mptsas_get_rphy(phy_info);
2526 if (!rphy) {
2527 dfailprintk((MYIOC_s_ERR_FMT
2528 "%s: exit at line=%d\n", ioc->name,
2529 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002530 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002531 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002532
Eric Moore547f9a22006-06-27 14:42:12 -06002533 port = mptsas_get_port(phy_info);
2534 if (!port) {
2535 dfailprintk((MYIOC_s_ERR_FMT
2536 "%s: exit at line=%d\n", ioc->name,
2537 __FUNCTION__, __LINE__));
2538 break;
2539 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002540
Eric Moore547f9a22006-06-27 14:42:12 -06002541 starget = mptsas_get_starget(phy_info);
2542 if (starget) {
2543 vtarget = starget->hostdata;
2544
2545 if (!vtarget) {
2546 dfailprintk((MYIOC_s_ERR_FMT
2547 "%s: exit at line=%d\n", ioc->name,
2548 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002549 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002550 }
2551
Moore, Ericf44e5462006-03-14 09:14:21 -07002552 /*
2553 * Handling RAID components
2554 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002555 if (ev->phys_disk_num_valid &&
2556 ev->hidden_raid_component) {
2557 printk(MYIOC_s_INFO_FMT
2558 "RAID Hidding: channel=%d, id=%d, "
2559 "physdsk %d \n", ioc->name, ev->channel,
2560 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002561 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002562 vtarget->tflags |=
2563 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002564 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002565 phy_info->attached.phys_disk_num =
2566 ev->phys_disk_num;
2567 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002568 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002569 }
2570
Eric Mooreb506ade2007-01-29 09:45:37 -07002571 if (phy_info->attached.device_info &
2572 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002573 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002574 if (phy_info->attached.device_info &
2575 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002576 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002577 if (phy_info->attached.device_info &
2578 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002579 ds = "sata";
2580
2581 printk(MYIOC_s_INFO_FMT
2582 "removing %s device, channel %d, id %d, phy %d\n",
2583 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore547f9a22006-06-27 14:42:12 -06002584#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002585 dev_printk(KERN_DEBUG, &port->dev,
2586 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002587#endif
2588 sas_port_delete(port);
2589 mptsas_port_delete(phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002590 break;
2591 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002592
Moore, Ericbd23e942006-04-17 12:43:04 -06002593 if (ev->phys_disk_num_valid)
2594 mpt_findImVolumes(ioc);
2595
Moore, Ericc73787ee2006-01-26 16:20:06 -07002596 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002597 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002598 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002599 if (mptsas_sas_device_pg0(ioc, &sas_device,
2600 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002601 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2602 (ev->channel << 8) + ev->id)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002603 dfailprintk((MYIOC_s_ERR_FMT
2604 "%s: exit at line=%d\n", ioc->name,
2605 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002606 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002607 }
2608
Eric Moore547f9a22006-06-27 14:42:12 -06002609 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002610
Eric Moore547f9a22006-06-27 14:42:12 -06002611 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2612 sas_device.sas_address);
2613
2614 if (!phy_info || !phy_info->port_details) {
2615 dfailprintk((MYIOC_s_ERR_FMT
2616 "%s: exit at line=%d\n", ioc->name,
2617 __FUNCTION__, __LINE__));
2618 break;
2619 }
2620
2621 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002622 if (starget && (!ev->hidden_raid_component)){
2623
Eric Moore547f9a22006-06-27 14:42:12 -06002624 vtarget = starget->hostdata;
2625
2626 if (!vtarget) {
2627 dfailprintk((MYIOC_s_ERR_FMT
2628 "%s: exit at line=%d\n", ioc->name,
2629 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002630 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002631 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002632 /*
2633 * Handling RAID components
2634 */
2635 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002636 printk(MYIOC_s_INFO_FMT
2637 "RAID Exposing: channel=%d, id=%d, "
2638 "physdsk %d \n", ioc->name, ev->channel,
2639 ev->id, ev->phys_disk_num);
2640 vtarget->tflags &=
2641 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002642 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002643 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002644 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002645 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002646 break;
2647 }
2648
Eric Moore547f9a22006-06-27 14:42:12 -06002649 if (mptsas_get_rphy(phy_info)) {
2650 dfailprintk((MYIOC_s_ERR_FMT
2651 "%s: exit at line=%d\n", ioc->name,
2652 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002653 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002654 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002655 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002656
Eric Moore547f9a22006-06-27 14:42:12 -06002657 port = mptsas_get_port(phy_info);
2658 if (!port) {
2659 dfailprintk((MYIOC_s_ERR_FMT
2660 "%s: exit at line=%d\n", ioc->name,
2661 __FUNCTION__, __LINE__));
2662 break;
2663 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002664 memcpy(&phy_info->attached, &sas_device,
2665 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002666
Eric Mooreb506ade2007-01-29 09:45:37 -07002667 if (phy_info->attached.device_info &
2668 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002669 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002670 if (phy_info->attached.device_info &
2671 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002672 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002673 if (phy_info->attached.device_info &
2674 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002675 ds = "sata";
2676
2677 printk(MYIOC_s_INFO_FMT
2678 "attaching %s device, channel %d, id %d, phy %d\n",
2679 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2680
James Bottomleyf013db32006-03-18 14:54:36 -06002681 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002682 rphy = sas_end_device_alloc(port);
2683 if (!rphy) {
2684 dfailprintk((MYIOC_s_ERR_FMT
2685 "%s: exit at line=%d\n", ioc->name,
2686 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002687 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002688 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002689
James Bottomleyf013db32006-03-18 14:54:36 -06002690 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002691 if (sas_rphy_add(rphy)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002692 dfailprintk((MYIOC_s_ERR_FMT
2693 "%s: exit at line=%d\n", ioc->name,
2694 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002695 sas_rphy_free(rphy);
2696 break;
2697 }
Eric Moore547f9a22006-06-27 14:42:12 -06002698 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002699 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002700 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002701 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2702 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002703 if (sdev) {
2704 scsi_device_put(sdev);
2705 break;
2706 }
2707 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002708 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002709 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2710 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002711 mpt_findImVolumes(ioc);
2712 break;
2713 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002714 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002715 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002716 if (!sdev)
2717 break;
2718 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002719 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002720 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002721 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002722 scsi_remove_device(sdev);
2723 scsi_device_put(sdev);
2724 mpt_findImVolumes(ioc);
2725 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002726 case MPTSAS_ADD_INACTIVE_VOLUME:
2727 mptsas_adding_inactive_raid_components(ioc,
2728 ev->channel, ev->id);
2729 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002730 case MPTSAS_IGNORE_EVENT:
2731 default:
2732 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002733 }
2734
Moore, Erice6b2d762006-03-14 09:14:24 -07002735 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002736 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002737}
2738
2739static void
Eric Moore547f9a22006-06-27 14:42:12 -06002740mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002741 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2742{
2743 struct mptsas_hotplug_event *ev;
2744 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2745 __le64 sas_address;
2746
2747 if ((device_info &
2748 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2749 MPI_SAS_DEVICE_INFO_STP_TARGET |
2750 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2751 return;
2752
Moore, Eric4b766472006-03-14 09:14:12 -07002753 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002754 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002755
2756 mptsas_target_reset_queue(ioc, sas_event_data);
2757 break;
2758
2759 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002760 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002761 if (!ev) {
2762 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2763 break;
2764 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002765
David Howellsc4028952006-11-22 14:57:56 +00002766 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002767 ev->ioc = ioc;
2768 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2769 ev->parent_handle =
2770 le16_to_cpu(sas_event_data->ParentDevHandle);
2771 ev->channel = sas_event_data->Bus;
2772 ev->id = sas_event_data->TargetID;
2773 ev->phy_id = sas_event_data->PhyNum;
2774 memcpy(&sas_address, &sas_event_data->SASAddress,
2775 sizeof(__le64));
2776 ev->sas_address = le64_to_cpu(sas_address);
2777 ev->device_info = device_info;
2778
2779 if (sas_event_data->ReasonCode &
2780 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2781 ev->event_type = MPTSAS_ADD_DEVICE;
2782 else
2783 ev->event_type = MPTSAS_DEL_DEVICE;
2784 schedule_work(&ev->work);
2785 break;
2786 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2787 /*
2788 * Persistent table is full.
2789 */
Eric Moore547f9a22006-06-27 14:42:12 -06002790 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002791 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002792 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002793 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002794 /*
2795 * TODO, handle other events
2796 */
Moore, Eric4b766472006-03-14 09:14:12 -07002797 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002798 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002799 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002800 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2801 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2802 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2803 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002804 default:
2805 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002806 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002807}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002808static void
Eric Moore547f9a22006-06-27 14:42:12 -06002809mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002810 EVENT_DATA_RAID *raid_event_data)
2811{
2812 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002813 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2814 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002815
2816 if (ioc->bus_type != SAS)
2817 return;
2818
Eric Moore547f9a22006-06-27 14:42:12 -06002819 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002820 if (!ev) {
2821 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2822 return;
2823 }
2824
David Howellsc4028952006-11-22 14:57:56 +00002825 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002826 ev->ioc = ioc;
2827 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002828 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002829 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002830
2831 switch (raid_event_data->ReasonCode) {
2832 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002833 ev->phys_disk_num_valid = 1;
2834 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002835 ev->event_type = MPTSAS_ADD_DEVICE;
2836 break;
2837 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002838 ev->phys_disk_num_valid = 1;
2839 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002840 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002841 ev->event_type = MPTSAS_DEL_DEVICE;
2842 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002843 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2844 switch (state) {
2845 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002846 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002847 ev->phys_disk_num_valid = 1;
2848 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002849 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002850 ev->event_type = MPTSAS_ADD_DEVICE;
2851 break;
2852 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002853 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2854 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2855 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002856 ev->phys_disk_num_valid = 1;
2857 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002858 ev->event_type = MPTSAS_DEL_DEVICE;
2859 break;
2860 default:
2861 break;
2862 }
2863 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002864 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2865 ev->event_type = MPTSAS_DEL_RAID;
2866 break;
2867 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2868 ev->event_type = MPTSAS_ADD_RAID;
2869 break;
2870 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002871 switch (state) {
2872 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2873 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2874 ev->event_type = MPTSAS_DEL_RAID;
2875 break;
2876 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2877 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2878 ev->event_type = MPTSAS_ADD_RAID;
2879 break;
2880 default:
2881 break;
2882 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002883 break;
2884 default:
2885 break;
2886 }
2887 schedule_work(&ev->work);
2888}
2889
Moore, Erice6b2d762006-03-14 09:14:24 -07002890static void
Eric Moore547f9a22006-06-27 14:42:12 -06002891mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002892 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2893{
2894 struct mptsas_discovery_event *ev;
2895
2896 /*
2897 * DiscoveryStatus
2898 *
2899 * This flag will be non-zero when firmware
2900 * kicks off discovery, and return to zero
2901 * once its completed.
2902 */
2903 if (discovery_data->DiscoveryStatus)
2904 return;
2905
Eric Moore547f9a22006-06-27 14:42:12 -06002906 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002907 if (!ev)
2908 return;
David Howellsc4028952006-11-22 14:57:56 +00002909 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002910 ev->ioc = ioc;
2911 schedule_work(&ev->work);
2912};
2913
Eric Mooreb506ade2007-01-29 09:45:37 -07002914/*
2915 * mptsas_send_ir2_event - handle exposing hidden disk when
2916 * an inactive raid volume is added
2917 *
2918 * @ioc: Pointer to MPT_ADAPTER structure
2919 * @ir2_data
2920 *
2921 */
2922static void
2923mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2924{
2925 struct mptsas_hotplug_event *ev;
2926
2927 if (ir2_data->ReasonCode !=
2928 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2929 return;
2930
2931 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2932 if (!ev)
2933 return;
2934
2935 INIT_WORK(&ev->work, mptsas_hotplug_work);
2936 ev->ioc = ioc;
2937 ev->id = ir2_data->TargetID;
2938 ev->channel = ir2_data->Bus;
2939 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
2940
2941 schedule_work(&ev->work);
2942};
Moore, Erice6b2d762006-03-14 09:14:24 -07002943
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002944static int
2945mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2946{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002947 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002948 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2949
2950 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002951 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002952
Moore, Erice6b2d762006-03-14 09:14:24 -07002953 /*
2954 * sas_discovery_ignore_events
2955 *
2956 * This flag is to prevent anymore processing of
2957 * sas events once mptsas_remove function is called.
2958 */
2959 if (ioc->sas_discovery_ignore_events) {
2960 rc = mptscsih_event_process(ioc, reply);
2961 goto out;
2962 }
2963
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002964 switch (event) {
2965 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06002966 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002967 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002968 break;
2969 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06002970 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002971 (EVENT_DATA_RAID *)reply->Data);
2972 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002973 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06002974 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002975 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002976 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07002977 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002978 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06002979 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002980 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2981 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002982 case MPI_EVENT_IR2:
2983 mptsas_send_ir2_event(ioc,
2984 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
2985 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002986 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002987 rc = mptscsih_event_process(ioc, reply);
2988 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002989 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002990 out:
2991
2992 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002993}
2994
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002995static int
2996mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2997{
2998 struct Scsi_Host *sh;
2999 MPT_SCSI_HOST *hd;
3000 MPT_ADAPTER *ioc;
3001 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003002 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003003 int numSGE = 0;
3004 int scale;
3005 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003006 int error=0;
3007 int r;
3008
3009 r = mpt_attach(pdev,id);
3010 if (r)
3011 return r;
3012
3013 ioc = pci_get_drvdata(pdev);
3014 ioc->DoneCtx = mptsasDoneCtx;
3015 ioc->TaskCtx = mptsasTaskCtx;
3016 ioc->InternalCtx = mptsasInternalCtx;
3017
3018 /* Added sanity check on readiness of the MPT adapter.
3019 */
3020 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3021 printk(MYIOC_s_WARN_FMT
3022 "Skipping because it's not operational!\n",
3023 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003024 error = -ENODEV;
3025 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003026 }
3027
3028 if (!ioc->active) {
3029 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3030 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003031 error = -ENODEV;
3032 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003033 }
3034
3035 /* Sanity check - ensure at least 1 port is INITIATOR capable
3036 */
3037 ioc_cap = 0;
3038 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3039 if (ioc->pfacts[ii].ProtocolFlags &
3040 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3041 ioc_cap++;
3042 }
3043
3044 if (!ioc_cap) {
3045 printk(MYIOC_s_WARN_FMT
3046 "Skipping ioc=%p because SCSI Initiator mode "
3047 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003048 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003049 }
3050
3051 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3052 if (!sh) {
3053 printk(MYIOC_s_WARN_FMT
3054 "Unable to register controller with SCSI subsystem\n",
3055 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003056 error = -1;
3057 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003058 }
3059
3060 spin_lock_irqsave(&ioc->FreeQlock, flags);
3061
3062 /* Attach the SCSI Host to the IOC structure
3063 */
3064 ioc->sh = sh;
3065
3066 sh->io_port = 0;
3067 sh->n_io_port = 0;
3068 sh->irq = 0;
3069
3070 /* set 16 byte cdb's */
3071 sh->max_cmd_len = 16;
3072
Eric Moore793955f2007-01-29 09:42:20 -07003073 sh->max_id = ioc->pfacts[0].PortSCSIID;
3074 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003075
3076 sh->transportt = mptsas_transport_template;
3077
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003078 sh->this_id = ioc->pfacts[0].PortSCSIID;
3079
3080 /* Required entry.
3081 */
3082 sh->unique_id = ioc->id;
3083
3084 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003085 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003086 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003087 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003088 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003089
3090 /* Verify that we won't exceed the maximum
3091 * number of chain buffers
3092 * We can optimize: ZZ = req_sz/sizeof(SGE)
3093 * For 32bit SGE's:
3094 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3095 * + (req_sz - 64)/sizeof(SGE)
3096 * A slightly different algorithm is required for
3097 * 64bit SGEs.
3098 */
3099 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3100 if (sizeof(dma_addr_t) == sizeof(u64)) {
3101 numSGE = (scale - 1) *
3102 (ioc->facts.MaxChainDepth-1) + scale +
3103 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3104 sizeof(u32));
3105 } else {
3106 numSGE = 1 + (scale - 1) *
3107 (ioc->facts.MaxChainDepth-1) + scale +
3108 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3109 sizeof(u32));
3110 }
3111
3112 if (numSGE < sh->sg_tablesize) {
3113 /* Reset this value */
3114 dprintk((MYIOC_s_INFO_FMT
3115 "Resetting sg_tablesize to %d from %d\n",
3116 ioc->name, numSGE, sh->sg_tablesize));
3117 sh->sg_tablesize = numSGE;
3118 }
3119
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003120 hd = (MPT_SCSI_HOST *) sh->hostdata;
3121 hd->ioc = ioc;
3122
3123 /* SCSI needs scsi_cmnd lookup table!
3124 * (with size equal to req_depth*PtrSz!)
3125 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003126 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3127 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003128 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003129 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003130 }
3131
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003132 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
3133 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003134
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003135 /* Clear the TM flags
3136 */
3137 hd->tmPending = 0;
3138 hd->tmState = TM_STATE_NONE;
3139 hd->resetPending = 0;
3140 hd->abortSCpnt = NULL;
3141
3142 /* Clear the pointer used to store
3143 * single-threaded commands, i.e., those
3144 * issued during a bus scan, dv and
3145 * configuration pages.
3146 */
3147 hd->cmdPtr = NULL;
3148
3149 /* Initialize this SCSI Hosts' timers
3150 * To use, set the timer expires field
3151 * and add_timer
3152 */
3153 init_timer(&hd->timer);
3154 hd->timer.data = (unsigned long) hd;
3155 hd->timer.function = mptscsih_timer_expired;
3156
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003157 ioc->sas_data.ptClear = mpt_pt_clear;
3158
Eric Mooredf9e0622007-01-29 09:46:21 -07003159 init_waitqueue_head(&hd->scandv_waitq);
3160 hd->scandv_wait_done = 0;
3161 hd->last_queue_full = 0;
3162 INIT_LIST_HEAD(&hd->target_reset_list);
3163 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3164
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003165 if (ioc->sas_data.ptClear==1) {
3166 mptbase_sas_persist_operation(
3167 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3168 }
3169
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003170 error = scsi_add_host(sh, &ioc->pcidev->dev);
3171 if (error) {
3172 dprintk((KERN_ERR MYNAM
3173 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003174 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003175 }
3176
3177 mptsas_scan_sas_topology(ioc);
3178
3179 return 0;
3180
Eric Moore547f9a22006-06-27 14:42:12 -06003181 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003182
3183 mptscsih_remove(pdev);
3184 return error;
3185}
3186
3187static void __devexit mptsas_remove(struct pci_dev *pdev)
3188{
3189 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3190 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003191 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192
Eric Mooreb506ade2007-01-29 09:45:37 -07003193 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003194 sas_remove_host(ioc->sh);
3195
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003196 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003197 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3198 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003199 for (i = 0 ; i < p->num_phys ; i++)
3200 mptsas_port_delete(p->phy_info[i].port_details);
3201 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003202 kfree(p);
3203 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003204 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003205
3206 mptscsih_remove(pdev);
3207}
3208
3209static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003210 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003211 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003212 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003213 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003214 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003215 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003216 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003217 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003218 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003219 PCI_ANY_ID, PCI_ANY_ID },
3220 {0} /* Terminating entry */
3221};
3222MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3223
3224
3225static struct pci_driver mptsas_driver = {
3226 .name = "mptsas",
3227 .id_table = mptsas_pci_table,
3228 .probe = mptsas_probe,
3229 .remove = __devexit_p(mptsas_remove),
3230 .shutdown = mptscsih_shutdown,
3231#ifdef CONFIG_PM
3232 .suspend = mptscsih_suspend,
3233 .resume = mptscsih_resume,
3234#endif
3235};
3236
3237static int __init
3238mptsas_init(void)
3239{
3240 show_mptmod_ver(my_NAME, my_VERSION);
3241
3242 mptsas_transport_template =
3243 sas_attach_transport(&mptsas_transport_functions);
3244 if (!mptsas_transport_template)
3245 return -ENODEV;
3246
3247 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003248 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249 mptsasInternalCtx =
3250 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003251 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003252
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003253 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07003254 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003255 ": Registered for IOC event notifications\n"));
3256 }
3257
Eric Mooredf9e0622007-01-29 09:46:21 -07003258 if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003259 dprintk((KERN_INFO MYNAM
3260 ": Registered for IOC reset notifications\n"));
3261 }
3262
3263 return pci_register_driver(&mptsas_driver);
3264}
3265
3266static void __exit
3267mptsas_exit(void)
3268{
3269 pci_unregister_driver(&mptsas_driver);
3270 sas_release_transport(mptsas_transport_template);
3271
3272 mpt_reset_deregister(mptsasDoneCtx);
3273 mpt_event_deregister(mptsasDoneCtx);
3274
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003275 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276 mpt_deregister(mptsasInternalCtx);
3277 mpt_deregister(mptsasTaskCtx);
3278 mpt_deregister(mptsasDoneCtx);
3279}
3280
3281module_init(mptsas_init);
3282module_exit(mptsas_exit);