blob: bc36f5fdb53e77acb57a20a1a93957377bebce03 [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 *
6 * Copyright (c) 1999-2005 LSI Logic Corporation
7 * (mailto:mpt_linux_developer@lsil.com)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01008 * Copyright (c) 2005-2006 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>
51#include <linux/sched.h>
52#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
70MODULE_AUTHOR(MODULEAUTHOR);
71MODULE_DESCRIPTION(my_NAME);
72MODULE_LICENSE("GPL");
73
74static int mpt_pq_filter;
75module_param(mpt_pq_filter, int, 0);
76MODULE_PARM_DESC(mpt_pq_filter,
77 "Enable peripheral qualifier filter: enable=1 "
78 "(default=0)");
79
80static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
83 "Clear persistency table: enable=1 "
84 "(default=MPTSCSIH_PT_CLEAR=0)");
85
86static int mptsasDoneCtx = -1;
87static int mptsasTaskCtx = -1;
88static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020089static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020090
91
Christoph Hellwig9a28f492006-01-13 18:04:41 +010092enum mptsas_hotplug_action {
93 MPTSAS_ADD_DEVICE,
94 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -070095 MPTSAS_ADD_RAID,
96 MPTSAS_DEL_RAID,
Moore, Ericbd23e942006-04-17 12:43:04 -060097 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +010098};
99
100struct mptsas_hotplug_event {
101 struct work_struct work;
102 MPT_ADAPTER *ioc;
103 enum mptsas_hotplug_action event_type;
104 u64 sas_address;
105 u32 channel;
106 u32 id;
107 u32 device_info;
108 u16 handle;
109 u16 parent_handle;
110 u8 phy_id;
Moore, Ericf44e5462006-03-14 09:14:21 -0700111 u8 phys_disk_num;
112 u8 phys_disk_num_valid;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100113};
114
Moore, Erice6b2d762006-03-14 09:14:24 -0700115struct mptsas_discovery_event {
116 struct work_struct work;
117 MPT_ADAPTER *ioc;
118};
119
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200120/*
121 * SAS topology structures
122 *
123 * The MPT Fusion firmware interface spreads information about the
124 * SAS topology over many manufacture pages, thus we need some data
125 * structure to collect it and process it for the SAS transport class.
126 */
127
128struct mptsas_devinfo {
129 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700130 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100131 u16 handle_enclosure; /* enclosure identifier of the enclosure */
132 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200133 u8 phy_id; /* phy number of parent device */
134 u8 port_id; /* sas physical port this device
135 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100136 u8 id; /* logical target id of this device */
137 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200138 u64 sas_address; /* WWN of this device,
139 SATA is assigned by HBA,expander */
140 u32 device_info; /* bitfield detailed info about this device */
141};
142
Eric Moore547f9a22006-06-27 14:42:12 -0600143/*
144 * Specific details on ports, wide/narrow
145 */
146struct mptsas_portinfo_details{
147 u8 port_id; /* port number provided to transport */
148 u16 num_phys; /* number of phys belong to this port */
149 u64 phy_bitmask; /* TODO, extend support for 255 phys */
150 struct sas_rphy *rphy; /* transport layer rphy object */
151 struct sas_port *port; /* transport layer port object */
152 struct scsi_target *starget;
153 struct mptsas_portinfo *port_info;
154};
155
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200156struct mptsas_phyinfo {
157 u8 phy_id; /* phy index */
Eric Moore547f9a22006-06-27 14:42:12 -0600158 u8 port_id; /* firmware port identifier */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200159 u8 negotiated_link_rate; /* nego'd link rate for this phy */
160 u8 hw_link_rate; /* hardware max/min phys link rate */
161 u8 programmed_link_rate; /* programmed max/min phy link rate */
Eric Moore547f9a22006-06-27 14:42:12 -0600162 u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200163 struct mptsas_devinfo identify; /* point to phy device info */
164 struct mptsas_devinfo attached; /* point to attached device info */
Eric Moore547f9a22006-06-27 14:42:12 -0600165 struct sas_phy *phy; /* transport layer phy object */
166 struct mptsas_portinfo *portinfo;
167 struct mptsas_portinfo_details * port_details;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200168};
169
170struct mptsas_portinfo {
171 struct list_head list;
172 u16 handle; /* unique id to address this */
Eric Moore547f9a22006-06-27 14:42:12 -0600173 u16 num_phys; /* number of phys */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200174 struct mptsas_phyinfo *phy_info;
175};
176
Christoph Hellwige3094442006-02-16 13:25:36 +0100177struct mptsas_enclosure {
178 u64 enclosure_logical_id; /* The WWN for the enclosure */
179 u16 enclosure_handle; /* unique id to address this */
180 u16 flags; /* details enclosure management */
181 u16 num_slot; /* num slots */
182 u16 start_slot; /* first slot */
183 u8 start_id; /* starting logical target id */
184 u8 start_channel; /* starting logical channel id */
185 u8 sep_id; /* SEP device logical target id */
186 u8 sep_channel; /* SEP channel logical channel id */
187};
188
Eric Moore547f9a22006-06-27 14:42:12 -0600189#ifdef MPT_DEBUG_SAS
Christoph Hellwigb5141122005-10-28 22:07:41 +0200190static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
191{
192 printk("---- IO UNIT PAGE 0 ------------\n");
193 printk("Handle=0x%X\n",
194 le16_to_cpu(phy_data->AttachedDeviceHandle));
195 printk("Controller Handle=0x%X\n",
196 le16_to_cpu(phy_data->ControllerDevHandle));
197 printk("Port=0x%X\n", phy_data->Port);
198 printk("Port Flags=0x%X\n", phy_data->PortFlags);
199 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
200 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
201 printk("Controller PHY Device Info=0x%X\n",
202 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
203 printk("DiscoveryStatus=0x%X\n",
204 le32_to_cpu(phy_data->DiscoveryStatus));
205 printk("\n");
206}
207
208static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
209{
210 __le64 sas_address;
211
212 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
213
214 printk("---- SAS PHY PAGE 0 ------------\n");
215 printk("Attached Device Handle=0x%X\n",
216 le16_to_cpu(pg0->AttachedDevHandle));
217 printk("SAS Address=0x%llX\n",
218 (unsigned long long)le64_to_cpu(sas_address));
219 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
220 printk("Attached Device Info=0x%X\n",
221 le32_to_cpu(pg0->AttachedDeviceInfo));
222 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
223 printk("Change Count=0x%X\n", pg0->ChangeCount);
224 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
225 printk("\n");
226}
227
228static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
229{
230 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200231 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
232 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200233 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200234 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
235 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
236 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200237}
238
239static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
240{
241 __le64 sas_address;
242
243 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
244
245 printk("---- SAS DEVICE PAGE 0 ---------\n");
246 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100247 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
249 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
250 printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
251 printk("Target ID=0x%X\n", pg0->TargetID);
252 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200253 /* The PhyNum field specifies the PHY number of the parent
254 * device this device is linked to
255 */
256 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
257 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200258 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
259 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
260 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
261 printk("\n");
262}
263
264static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
265{
266 printk("---- SAS EXPANDER PAGE 1 ------------\n");
267
268 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200269 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200270 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
271 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
272 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
273 printk("Owner Device Handle=0x%X\n",
274 le16_to_cpu(pg1->OwnerDevHandle));
275 printk("Attached Device Handle=0x%X\n",
276 le16_to_cpu(pg1->AttachedDevHandle));
277}
278#else
279#define mptsas_print_phy_data(phy_data) do { } while (0)
280#define mptsas_print_phy_pg0(pg0) do { } while (0)
281#define mptsas_print_phy_pg1(pg1) do { } while (0)
282#define mptsas_print_device_pg0(pg0) do { } while (0)
283#define mptsas_print_expander_pg1(pg1) do { } while (0)
284#endif
285
Christoph Hellwige3094442006-02-16 13:25:36 +0100286static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
287{
288 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
289 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
290}
291
292static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
293{
294 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
295 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
296}
297
Moore, Erice6b2d762006-03-14 09:14:24 -0700298/*
299 * mptsas_find_portinfo_by_handle
300 *
301 * This function should be called with the sas_topology_mutex already held
302 */
303static struct mptsas_portinfo *
304mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
305{
306 struct mptsas_portinfo *port_info, *rc=NULL;
307 int i;
308
309 list_for_each_entry(port_info, &ioc->sas_topology, list)
310 for (i = 0; i < port_info->num_phys; i++)
311 if (port_info->phy_info[i].identify.handle == handle) {
312 rc = port_info;
313 goto out;
314 }
315 out:
316 return rc;
317}
318
Moore, Ericbd23e942006-04-17 12:43:04 -0600319/*
320 * Returns true if there is a scsi end device
321 */
322static inline int
323mptsas_is_end_device(struct mptsas_devinfo * attached)
324{
Eric Moore547f9a22006-06-27 14:42:12 -0600325 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600326 (attached->device_info &
327 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
328 ((attached->device_info &
329 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
330 (attached->device_info &
331 MPI_SAS_DEVICE_INFO_STP_TARGET) |
332 (attached->device_info &
333 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
334 return 1;
335 else
336 return 0;
337}
338
Eric Moore547f9a22006-06-27 14:42:12 -0600339/* no mutex */
340void
341mptsas_port_delete(struct mptsas_portinfo_details * port_details)
342{
343 struct mptsas_portinfo *port_info;
344 struct mptsas_phyinfo *phy_info;
345 u8 i;
346
347 if (!port_details)
348 return;
349
350 port_info = port_details->port_info;
351 phy_info = port_info->phy_info;
352
353 dsaswideprintk((KERN_DEBUG "%s: [%p]: port=%02d num_phys=%02d "
354 "bitmask=0x%016llX\n",
355 __FUNCTION__, port_details, port_details->port_id,
356 port_details->num_phys, port_details->phy_bitmask));
357
358 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
359 if(phy_info->port_details != port_details)
360 continue;
361 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
362 phy_info->port_details = NULL;
363 }
364 kfree(port_details);
365}
366
367static inline struct sas_rphy *
368mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
369{
370 if (phy_info->port_details)
371 return phy_info->port_details->rphy;
372 else
373 return NULL;
374}
375
376static inline void
377mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
378{
379 if (phy_info->port_details) {
380 phy_info->port_details->rphy = rphy;
381 dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
382 }
383
384#ifdef MPT_DEBUG_SAS_WIDE
385 if (rphy) {
386 dev_printk(KERN_DEBUG, &rphy->dev, "add:");
387 printk("rphy=%p release=%p\n",
388 rphy, rphy->dev.release);
389 }
390#endif
391}
392
393static inline struct sas_port *
394mptsas_get_port(struct mptsas_phyinfo *phy_info)
395{
396 if (phy_info->port_details)
397 return phy_info->port_details->port;
398 else
399 return NULL;
400}
401
402static inline void
403mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
404{
405 if (phy_info->port_details)
406 phy_info->port_details->port = port;
407
408#ifdef MPT_DEBUG_SAS_WIDE
409 if (port) {
410 dev_printk(KERN_DEBUG, &port->dev, "add: ");
411 printk("port=%p release=%p\n",
412 port, port->dev.release);
413 }
414#endif
415}
416
417static inline struct scsi_target *
418mptsas_get_starget(struct mptsas_phyinfo *phy_info)
419{
420 if (phy_info->port_details)
421 return phy_info->port_details->starget;
422 else
423 return NULL;
424}
425
426static inline void
427mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
428starget)
429{
430 if (phy_info->port_details)
431 phy_info->port_details->starget = starget;
432}
433
434
435/*
436 * mptsas_setup_wide_ports
437 *
438 * Updates for new and existing narrow/wide port configuration
439 * in the sas_topology
440 */
441void
442mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
443{
444 struct mptsas_portinfo_details * port_details;
445 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
446 u64 sas_address;
447 int i, j;
448
449 mutex_lock(&ioc->sas_topology_mutex);
450
451 phy_info = port_info->phy_info;
452 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
453 if (phy_info->attached.handle)
454 continue;
455 port_details = phy_info->port_details;
456 if (!port_details)
457 continue;
458 if (port_details->num_phys < 2)
459 continue;
460 /*
461 * Removing a phy from a port, letting the last
462 * phy be removed by firmware events.
463 */
464 dsaswideprintk((KERN_DEBUG
465 "%s: [%p]: port=%d deleting phy = %d\n",
466 __FUNCTION__, port_details,
467 port_details->port_id, i));
468 port_details->num_phys--;
469 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
470 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
471 sas_port_delete_phy(port_details->port, phy_info->phy);
472 phy_info->port_details = NULL;
473 }
474
475 /*
476 * Populate and refresh the tree
477 */
478 phy_info = port_info->phy_info;
479 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
480 sas_address = phy_info->attached.sas_address;
481 dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
482 i, sas_address));
483 if (!sas_address)
484 continue;
485 port_details = phy_info->port_details;
486 /*
487 * Forming a port
488 */
489 if (!port_details) {
490 port_details = kzalloc(sizeof(*port_details),
491 GFP_KERNEL);
492 if (!port_details)
493 goto out;
494 port_details->num_phys = 1;
495 port_details->port_info = port_info;
496 port_details->port_id = ioc->port_serial_number++;
497 if (phy_info->phy_id < 64 )
498 port_details->phy_bitmask |=
499 (1 << phy_info->phy_id);
500 phy_info->sas_port_add_phy=1;
501 dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
502 "phy_id=%d sas_address=0x%018llX\n",
503 i, sas_address));
504 phy_info->port_details = port_details;
505 }
506
507 if (i == port_info->num_phys - 1)
508 continue;
509 phy_info_cmp = &port_info->phy_info[i + 1];
510 for (j = i + 1 ; j < port_info->num_phys ; j++,
511 phy_info_cmp++) {
512 if (!phy_info_cmp->attached.sas_address)
513 continue;
514 if (sas_address != phy_info_cmp->attached.sas_address)
515 continue;
516 if (phy_info_cmp->port_details == port_details )
517 continue;
518 dsaswideprintk((KERN_DEBUG
519 "\t\tphy_id=%d sas_address=0x%018llX\n",
520 j, phy_info_cmp->attached.sas_address));
521 if (phy_info_cmp->port_details) {
522 port_details->rphy =
523 mptsas_get_rphy(phy_info_cmp);
524 port_details->port =
525 mptsas_get_port(phy_info_cmp);
526 port_details->starget =
527 mptsas_get_starget(phy_info_cmp);
528 port_details->port_id =
529 phy_info_cmp->port_details->port_id;
530 port_details->num_phys =
531 phy_info_cmp->port_details->num_phys;
532// port_info->port_serial_number--;
533 ioc->port_serial_number--;
534 if (!phy_info_cmp->port_details->num_phys)
535 kfree(phy_info_cmp->port_details);
536 } else
537 phy_info_cmp->sas_port_add_phy=1;
538 /*
539 * Adding a phy to a port
540 */
541 phy_info_cmp->port_details = port_details;
542 if (phy_info_cmp->phy_id < 64 )
543 port_details->phy_bitmask |=
544 (1 << phy_info_cmp->phy_id);
545 port_details->num_phys++;
546 }
547 }
548
549 out:
550
551#ifdef MPT_DEBUG_SAS_WIDE
552 for (i = 0; i < port_info->num_phys; i++) {
553 port_details = port_info->phy_info[i].port_details;
554 if (!port_details)
555 continue;
556 dsaswideprintk((KERN_DEBUG
557 "%s: [%p]: phy_id=%02d port_id=%02d num_phys=%02d "
558 "bitmask=0x%016llX\n",
559 __FUNCTION__,
560 port_details, i, port_details->port_id,
561 port_details->num_phys, port_details->phy_bitmask));
562 dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
563 port_details->port, port_details->rphy));
564 }
565 dsaswideprintk((KERN_DEBUG"\n"));
566#endif
567 mutex_unlock(&ioc->sas_topology_mutex);
568}
569
570static void
571mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget)
572{
573 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
574
575 if (mptscsih_TMHandler(hd,
576 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
577 vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) {
578 hd->tmPending = 0;
579 hd->tmState = TM_STATE_NONE;
580 printk(MYIOC_s_WARN_FMT
581 "Error processing TaskMgmt id=%d TARGET_RESET\n",
582 ioc->name, vtarget->target_id);
583 }
584}
585
Christoph Hellwige3094442006-02-16 13:25:36 +0100586static int
Moore, Eric52435432006-03-14 09:14:15 -0700587mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100588 u32 form, u32 form_specific)
589{
590 ConfigExtendedPageHeader_t hdr;
591 CONFIGPARMS cfg;
592 SasEnclosurePage0_t *buffer;
593 dma_addr_t dma_handle;
594 int error;
595 __le64 le_identifier;
596
597 memset(&hdr, 0, sizeof(hdr));
598 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
599 hdr.PageNumber = 0;
600 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
601 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
602
603 cfg.cfghdr.ehdr = &hdr;
604 cfg.physAddr = -1;
605 cfg.pageAddr = form + form_specific;
606 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
607 cfg.dir = 0; /* read */
608 cfg.timeout = 10;
609
610 error = mpt_config(ioc, &cfg);
611 if (error)
612 goto out;
613 if (!hdr.ExtPageLength) {
614 error = -ENXIO;
615 goto out;
616 }
617
618 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
619 &dma_handle);
620 if (!buffer) {
621 error = -ENOMEM;
622 goto out;
623 }
624
625 cfg.physAddr = dma_handle;
626 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
627
628 error = mpt_config(ioc, &cfg);
629 if (error)
630 goto out_free_consistent;
631
632 /* save config data */
633 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
634 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
635 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
636 enclosure->flags = le16_to_cpu(buffer->Flags);
637 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
638 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
639 enclosure->start_id = buffer->StartTargetID;
640 enclosure->start_channel = buffer->StartBus;
641 enclosure->sep_id = buffer->SEPTargetID;
642 enclosure->sep_channel = buffer->SEPBus;
643
644 out_free_consistent:
645 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
646 buffer, dma_handle);
647 out:
648 return error;
649}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200650
James Bottomleyf013db32006-03-18 14:54:36 -0600651static int
652mptsas_slave_configure(struct scsi_device *sdev)
653{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600654 struct Scsi_Host *host = sdev->host;
655 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
656
657 /*
658 * RAID volumes placed beyond the last expected port.
659 * Ignore sending sas mode pages in that case..
660 */
661 if (sdev->channel < hd->ioc->num_ports)
662 sas_read_port_mode_page(sdev);
James Bottomleyf013db32006-03-18 14:54:36 -0600663
664 return mptscsih_slave_configure(sdev);
665}
666
Eric Moore547f9a22006-06-27 14:42:12 -0600667static int
668mptsas_target_alloc(struct scsi_target *starget)
669{
670 struct Scsi_Host *host = dev_to_shost(&starget->dev);
671 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
672 VirtTarget *vtarget;
673 u32 target_id;
674 u32 channel;
675 struct sas_rphy *rphy;
676 struct mptsas_portinfo *p;
677 int i;
678
679 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
680 if (!vtarget)
681 return -ENOMEM;
682
683 vtarget->starget = starget;
684 vtarget->ioc_id = hd->ioc->id;
685 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
686
687 target_id = starget->id;
688 channel = 0;
689
690 hd->Targets[target_id] = vtarget;
691
692 /*
693 * RAID volumes placed beyond the last expected port.
694 */
695 if (starget->channel == hd->ioc->num_ports)
696 goto out;
697
698 rphy = dev_to_rphy(starget->dev.parent);
699 mutex_lock(&hd->ioc->sas_topology_mutex);
700 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
701 for (i = 0; i < p->num_phys; i++) {
702 if (p->phy_info[i].attached.sas_address !=
703 rphy->identify.sas_address)
704 continue;
705 target_id = p->phy_info[i].attached.id;
706 channel = p->phy_info[i].attached.channel;
707 mptsas_set_starget(&p->phy_info[i], starget);
708
709 /*
710 * Exposing hidden raid components
711 */
712 if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
713 target_id = mptscsih_raid_id_to_num(hd,
714 target_id);
715 vtarget->tflags |=
716 MPT_TARGET_FLAGS_RAID_COMPONENT;
717 }
718 mutex_unlock(&hd->ioc->sas_topology_mutex);
719 goto out;
720 }
721 }
722 mutex_unlock(&hd->ioc->sas_topology_mutex);
723
724 kfree(vtarget);
725 return -ENXIO;
726
727 out:
728 vtarget->target_id = target_id;
729 vtarget->bus_id = channel;
730 starget->hostdata = vtarget;
731 return 0;
732}
733
734static void
735mptsas_target_destroy(struct scsi_target *starget)
736{
737 struct Scsi_Host *host = dev_to_shost(&starget->dev);
738 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
739 struct sas_rphy *rphy;
740 struct mptsas_portinfo *p;
741 int i;
742
743 if (!starget->hostdata)
744 return;
745
746 if (starget->channel == hd->ioc->num_ports)
747 goto out;
748
749 rphy = dev_to_rphy(starget->dev.parent);
750 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
751 for (i = 0; i < p->num_phys; i++) {
752 if (p->phy_info[i].attached.sas_address !=
753 rphy->identify.sas_address)
754 continue;
755 mptsas_set_starget(&p->phy_info[i], NULL);
756 goto out;
757 }
758 }
759
760 out:
761 kfree(starget->hostdata);
762 starget->hostdata = NULL;
763}
764
765
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200766static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700767mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200768{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700769 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200770 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
771 struct sas_rphy *rphy;
772 struct mptsas_portinfo *p;
773 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700774 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600775 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200776
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100777 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200778 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -0600779 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200780 hd->ioc->name, sizeof(VirtDevice));
781 return -ENOMEM;
782 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700783 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -0600784 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200785
Moore, Eric816aa902006-01-13 16:25:20 -0700786 /*
Eric Moore547f9a22006-06-27 14:42:12 -0600787 * RAID volumes placed beyond the last expected port.
788 */
789 if (sdev->channel == hd->ioc->num_ports)
Moore, Eric816aa902006-01-13 16:25:20 -0700790 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700791
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700792 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100793 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200794 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
795 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600796 if (p->phy_info[i].attached.sas_address !=
797 rphy->identify.sas_address)
798 continue;
799 vdev->lun = sdev->lun;
800 /*
801 * Exposing hidden raid components
802 */
803 if (mptscsih_is_phys_disk(hd->ioc,
804 p->phy_info[i].attached.id))
805 sdev->no_uld_attach = 1;
806 mutex_unlock(&hd->ioc->sas_topology_mutex);
807 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200808 }
809 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100810 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200811
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200812 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100813 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200814
815 out:
Eric Moore547f9a22006-06-27 14:42:12 -0600816 vdev->vtarget->num_luns++;
817 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200818 return 0;
819}
820
Eric Moore547f9a22006-06-27 14:42:12 -0600821static int
822mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100823{
Eric Moore547f9a22006-06-27 14:42:12 -0600824 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100825
Eric Moore547f9a22006-06-27 14:42:12 -0600826// scsi_print_command(SCpnt);
827 if (vdev->vtarget->deleted) {
828 SCpnt->result = DID_NO_CONNECT << 16;
829 done(SCpnt);
830 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700831 }
Eric Moore547f9a22006-06-27 14:42:12 -0600832
833 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100834}
835
Eric Moore547f9a22006-06-27 14:42:12 -0600836
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200837static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700838 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200839 .proc_name = "mptsas",
840 .proc_info = mptscsih_proc_info,
841 .name = "MPT SPI Host",
842 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -0600843 .queuecommand = mptsas_qcmd,
844 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200845 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -0600846 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -0600847 .target_destroy = mptsas_target_destroy,
848 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200849 .change_queue_depth = mptscsih_change_queue_depth,
850 .eh_abort_handler = mptscsih_abort,
851 .eh_device_reset_handler = mptscsih_dev_reset,
852 .eh_bus_reset_handler = mptscsih_bus_reset,
853 .eh_host_reset_handler = mptscsih_host_reset,
854 .bios_param = mptscsih_bios_param,
855 .can_queue = MPT_FC_CAN_QUEUE,
856 .this_id = -1,
857 .sg_tablesize = MPT_SCSI_SG_DEPTH,
858 .max_sectors = 8192,
859 .cmd_per_lun = 7,
860 .use_clustering = ENABLE_CLUSTERING,
861};
862
Christoph Hellwigb5141122005-10-28 22:07:41 +0200863static int mptsas_get_linkerrors(struct sas_phy *phy)
864{
865 MPT_ADAPTER *ioc = phy_to_ioc(phy);
866 ConfigExtendedPageHeader_t hdr;
867 CONFIGPARMS cfg;
868 SasPhyPage1_t *buffer;
869 dma_addr_t dma_handle;
870 int error;
871
872 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
873 hdr.ExtPageLength = 0;
874 hdr.PageNumber = 1 /* page number 1*/;
875 hdr.Reserved1 = 0;
876 hdr.Reserved2 = 0;
877 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
878 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
879
880 cfg.cfghdr.ehdr = &hdr;
881 cfg.physAddr = -1;
882 cfg.pageAddr = phy->identify.phy_identifier;
883 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
884 cfg.dir = 0; /* read */
885 cfg.timeout = 10;
886
887 error = mpt_config(ioc, &cfg);
888 if (error)
889 return error;
890 if (!hdr.ExtPageLength)
891 return -ENXIO;
892
893 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
894 &dma_handle);
895 if (!buffer)
896 return -ENOMEM;
897
898 cfg.physAddr = dma_handle;
899 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
900
901 error = mpt_config(ioc, &cfg);
902 if (error)
903 goto out_free_consistent;
904
905 mptsas_print_phy_pg1(buffer);
906
907 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
908 phy->running_disparity_error_count =
909 le32_to_cpu(buffer->RunningDisparityErrorCount);
910 phy->loss_of_dword_sync_count =
911 le32_to_cpu(buffer->LossDwordSynchCount);
912 phy->phy_reset_problem_count =
913 le32_to_cpu(buffer->PhyResetProblemCount);
914
915 out_free_consistent:
916 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
917 buffer, dma_handle);
918 return error;
919}
920
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200921static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
922 MPT_FRAME_HDR *reply)
923{
924 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
925 if (reply != NULL) {
926 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
927 memcpy(ioc->sas_mgmt.reply, reply,
928 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
929 }
930 complete(&ioc->sas_mgmt.done);
931 return 1;
932}
933
934static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
935{
936 MPT_ADAPTER *ioc = phy_to_ioc(phy);
937 SasIoUnitControlRequest_t *req;
938 SasIoUnitControlReply_t *reply;
939 MPT_FRAME_HDR *mf;
940 MPIHeader_t *hdr;
941 unsigned long timeleft;
942 int error = -ERESTARTSYS;
943
944 /* not implemented for expanders */
945 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
946 return -ENXIO;
947
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100948 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200949 goto out;
950
951 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
952 if (!mf) {
953 error = -ENOMEM;
954 goto out_unlock;
955 }
956
957 hdr = (MPIHeader_t *) mf;
958 req = (SasIoUnitControlRequest_t *)mf;
959 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
960 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
961 req->MsgContext = hdr->MsgContext;
962 req->Operation = hard_reset ?
963 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
964 req->PhyNum = phy->identify.phy_identifier;
965
966 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
967
968 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
969 10 * HZ);
970 if (!timeleft) {
971 /* On timeout reset the board */
972 mpt_free_msg_frame(ioc, mf);
973 mpt_HardResetHandler(ioc, CAN_SLEEP);
974 error = -ETIMEDOUT;
975 goto out_unlock;
976 }
977
978 /* a reply frame is expected */
979 if ((ioc->sas_mgmt.status &
980 MPT_IOCTL_STATUS_RF_VALID) == 0) {
981 error = -ENXIO;
982 goto out_unlock;
983 }
984
985 /* process the completed Reply Message Frame */
986 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
987 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
988 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
989 __FUNCTION__,
990 reply->IOCStatus,
991 reply->IOCLogInfo);
992 error = -ENXIO;
993 goto out_unlock;
994 }
995
996 error = 0;
997
998 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100999 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001000 out:
1001 return error;
1002}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001003
Christoph Hellwige3094442006-02-16 13:25:36 +01001004static int
1005mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1006{
1007 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1008 int i, error;
1009 struct mptsas_portinfo *p;
1010 struct mptsas_enclosure enclosure_info;
1011 u64 enclosure_handle;
1012
1013 mutex_lock(&ioc->sas_topology_mutex);
1014 list_for_each_entry(p, &ioc->sas_topology, list) {
1015 for (i = 0; i < p->num_phys; i++) {
1016 if (p->phy_info[i].attached.sas_address ==
1017 rphy->identify.sas_address) {
1018 enclosure_handle = p->phy_info[i].
1019 attached.handle_enclosure;
1020 goto found_info;
1021 }
1022 }
1023 }
1024 mutex_unlock(&ioc->sas_topology_mutex);
1025 return -ENXIO;
1026
1027 found_info:
1028 mutex_unlock(&ioc->sas_topology_mutex);
1029 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001030 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001031 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1032 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1033 if (!error)
1034 *identifier = enclosure_info.enclosure_logical_id;
1035 return error;
1036}
1037
1038static int
1039mptsas_get_bay_identifier(struct sas_rphy *rphy)
1040{
1041 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1042 struct mptsas_portinfo *p;
1043 int i, rc;
1044
1045 mutex_lock(&ioc->sas_topology_mutex);
1046 list_for_each_entry(p, &ioc->sas_topology, list) {
1047 for (i = 0; i < p->num_phys; i++) {
1048 if (p->phy_info[i].attached.sas_address ==
1049 rphy->identify.sas_address) {
1050 rc = p->phy_info[i].attached.slot;
1051 goto out;
1052 }
1053 }
1054 }
1055 rc = -ENXIO;
1056 out:
1057 mutex_unlock(&ioc->sas_topology_mutex);
1058 return rc;
1059}
1060
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001061static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001062 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001063 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1064 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001065 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001066};
1067
1068static struct scsi_transport_template *mptsas_transport_template;
1069
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001070static int
1071mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1072{
1073 ConfigExtendedPageHeader_t hdr;
1074 CONFIGPARMS cfg;
1075 SasIOUnitPage0_t *buffer;
1076 dma_addr_t dma_handle;
1077 int error, i;
1078
1079 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1080 hdr.ExtPageLength = 0;
1081 hdr.PageNumber = 0;
1082 hdr.Reserved1 = 0;
1083 hdr.Reserved2 = 0;
1084 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1085 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1086
1087 cfg.cfghdr.ehdr = &hdr;
1088 cfg.physAddr = -1;
1089 cfg.pageAddr = 0;
1090 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1091 cfg.dir = 0; /* read */
1092 cfg.timeout = 10;
1093
1094 error = mpt_config(ioc, &cfg);
1095 if (error)
1096 goto out;
1097 if (!hdr.ExtPageLength) {
1098 error = -ENXIO;
1099 goto out;
1100 }
1101
1102 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1103 &dma_handle);
1104 if (!buffer) {
1105 error = -ENOMEM;
1106 goto out;
1107 }
1108
1109 cfg.physAddr = dma_handle;
1110 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1111
1112 error = mpt_config(ioc, &cfg);
1113 if (error)
1114 goto out_free_consistent;
1115
1116 port_info->num_phys = buffer->NumPhys;
1117 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001118 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001119 if (!port_info->phy_info) {
1120 error = -ENOMEM;
1121 goto out_free_consistent;
1122 }
1123
Moore, Ericdb9c9172006-03-14 09:14:18 -07001124 if (port_info->num_phys)
1125 port_info->handle =
1126 le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001127 for (i = 0; i < port_info->num_phys; i++) {
1128 mptsas_print_phy_data(&buffer->PhyData[i]);
1129 port_info->phy_info[i].phy_id = i;
1130 port_info->phy_info[i].port_id =
1131 buffer->PhyData[i].Port;
1132 port_info->phy_info[i].negotiated_link_rate =
1133 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001134 port_info->phy_info[i].portinfo = port_info;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001135 }
1136
1137 out_free_consistent:
1138 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1139 buffer, dma_handle);
1140 out:
1141 return error;
1142}
1143
1144static int
1145mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1146 u32 form, u32 form_specific)
1147{
1148 ConfigExtendedPageHeader_t hdr;
1149 CONFIGPARMS cfg;
1150 SasPhyPage0_t *buffer;
1151 dma_addr_t dma_handle;
1152 int error;
1153
1154 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1155 hdr.ExtPageLength = 0;
1156 hdr.PageNumber = 0;
1157 hdr.Reserved1 = 0;
1158 hdr.Reserved2 = 0;
1159 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1160 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1161
1162 cfg.cfghdr.ehdr = &hdr;
1163 cfg.dir = 0; /* read */
1164 cfg.timeout = 10;
1165
1166 /* Get Phy Pg 0 for each Phy. */
1167 cfg.physAddr = -1;
1168 cfg.pageAddr = form + form_specific;
1169 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1170
1171 error = mpt_config(ioc, &cfg);
1172 if (error)
1173 goto out;
1174
1175 if (!hdr.ExtPageLength) {
1176 error = -ENXIO;
1177 goto out;
1178 }
1179
1180 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1181 &dma_handle);
1182 if (!buffer) {
1183 error = -ENOMEM;
1184 goto out;
1185 }
1186
1187 cfg.physAddr = dma_handle;
1188 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1189
1190 error = mpt_config(ioc, &cfg);
1191 if (error)
1192 goto out_free_consistent;
1193
1194 mptsas_print_phy_pg0(buffer);
1195
1196 phy_info->hw_link_rate = buffer->HwLinkRate;
1197 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1198 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1199 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1200
1201 out_free_consistent:
1202 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1203 buffer, dma_handle);
1204 out:
1205 return error;
1206}
1207
1208static int
1209mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1210 u32 form, u32 form_specific)
1211{
1212 ConfigExtendedPageHeader_t hdr;
1213 CONFIGPARMS cfg;
1214 SasDevicePage0_t *buffer;
1215 dma_addr_t dma_handle;
1216 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001217 int error=0;
1218
1219 if (ioc->sas_discovery_runtime &&
1220 mptsas_is_end_device(device_info))
1221 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001222
1223 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1224 hdr.ExtPageLength = 0;
1225 hdr.PageNumber = 0;
1226 hdr.Reserved1 = 0;
1227 hdr.Reserved2 = 0;
1228 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1229 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1230
1231 cfg.cfghdr.ehdr = &hdr;
1232 cfg.pageAddr = form + form_specific;
1233 cfg.physAddr = -1;
1234 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1235 cfg.dir = 0; /* read */
1236 cfg.timeout = 10;
1237
Moore, Ericdb9c9172006-03-14 09:14:18 -07001238 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001239 error = mpt_config(ioc, &cfg);
1240 if (error)
1241 goto out;
1242 if (!hdr.ExtPageLength) {
1243 error = -ENXIO;
1244 goto out;
1245 }
1246
1247 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1248 &dma_handle);
1249 if (!buffer) {
1250 error = -ENOMEM;
1251 goto out;
1252 }
1253
1254 cfg.physAddr = dma_handle;
1255 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1256
1257 error = mpt_config(ioc, &cfg);
1258 if (error)
1259 goto out_free_consistent;
1260
1261 mptsas_print_device_pg0(buffer);
1262
1263 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001264 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001265 device_info->handle_enclosure =
1266 le16_to_cpu(buffer->EnclosureHandle);
1267 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001268 device_info->phy_id = buffer->PhyNum;
1269 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001270 device_info->id = buffer->TargetID;
1271 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001272 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1273 device_info->sas_address = le64_to_cpu(sas_address);
1274 device_info->device_info =
1275 le32_to_cpu(buffer->DeviceInfo);
1276
1277 out_free_consistent:
1278 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1279 buffer, dma_handle);
1280 out:
1281 return error;
1282}
1283
1284static int
1285mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1286 u32 form, u32 form_specific)
1287{
1288 ConfigExtendedPageHeader_t hdr;
1289 CONFIGPARMS cfg;
1290 SasExpanderPage0_t *buffer;
1291 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001292 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001293
1294 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1295 hdr.ExtPageLength = 0;
1296 hdr.PageNumber = 0;
1297 hdr.Reserved1 = 0;
1298 hdr.Reserved2 = 0;
1299 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1300 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1301
1302 cfg.cfghdr.ehdr = &hdr;
1303 cfg.physAddr = -1;
1304 cfg.pageAddr = form + form_specific;
1305 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1306 cfg.dir = 0; /* read */
1307 cfg.timeout = 10;
1308
Moore, Ericdb9c9172006-03-14 09:14:18 -07001309 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001310 error = mpt_config(ioc, &cfg);
1311 if (error)
1312 goto out;
1313
1314 if (!hdr.ExtPageLength) {
1315 error = -ENXIO;
1316 goto out;
1317 }
1318
1319 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1320 &dma_handle);
1321 if (!buffer) {
1322 error = -ENOMEM;
1323 goto out;
1324 }
1325
1326 cfg.physAddr = dma_handle;
1327 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1328
1329 error = mpt_config(ioc, &cfg);
1330 if (error)
1331 goto out_free_consistent;
1332
1333 /* save config data */
1334 port_info->num_phys = buffer->NumPhys;
1335 port_info->handle = le16_to_cpu(buffer->DevHandle);
1336 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001337 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001338 if (!port_info->phy_info) {
1339 error = -ENOMEM;
1340 goto out_free_consistent;
1341 }
1342
Eric Moore547f9a22006-06-27 14:42:12 -06001343 for (i = 0; i < port_info->num_phys; i++)
1344 port_info->phy_info[i].portinfo = port_info;
1345
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001346 out_free_consistent:
1347 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1348 buffer, dma_handle);
1349 out:
1350 return error;
1351}
1352
1353static int
1354mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1355 u32 form, u32 form_specific)
1356{
1357 ConfigExtendedPageHeader_t hdr;
1358 CONFIGPARMS cfg;
1359 SasExpanderPage1_t *buffer;
1360 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001361 int error=0;
1362
1363 if (ioc->sas_discovery_runtime &&
1364 mptsas_is_end_device(&phy_info->attached))
1365 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001366
1367 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1368 hdr.ExtPageLength = 0;
1369 hdr.PageNumber = 1;
1370 hdr.Reserved1 = 0;
1371 hdr.Reserved2 = 0;
1372 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1373 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1374
1375 cfg.cfghdr.ehdr = &hdr;
1376 cfg.physAddr = -1;
1377 cfg.pageAddr = form + form_specific;
1378 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1379 cfg.dir = 0; /* read */
1380 cfg.timeout = 10;
1381
1382 error = mpt_config(ioc, &cfg);
1383 if (error)
1384 goto out;
1385
1386 if (!hdr.ExtPageLength) {
1387 error = -ENXIO;
1388 goto out;
1389 }
1390
1391 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1392 &dma_handle);
1393 if (!buffer) {
1394 error = -ENOMEM;
1395 goto out;
1396 }
1397
1398 cfg.physAddr = dma_handle;
1399 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1400
1401 error = mpt_config(ioc, &cfg);
1402 if (error)
1403 goto out_free_consistent;
1404
1405
1406 mptsas_print_expander_pg1(buffer);
1407
1408 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001409 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001410 phy_info->port_id = buffer->PhysicalPort;
1411 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1412 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1413 phy_info->hw_link_rate = buffer->HwLinkRate;
1414 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1415 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1416
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001417 out_free_consistent:
1418 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1419 buffer, dma_handle);
1420 out:
1421 return error;
1422}
1423
1424static void
1425mptsas_parse_device_info(struct sas_identify *identify,
1426 struct mptsas_devinfo *device_info)
1427{
1428 u16 protocols;
1429
1430 identify->sas_address = device_info->sas_address;
1431 identify->phy_identifier = device_info->phy_id;
1432
1433 /*
1434 * Fill in Phy Initiator Port Protocol.
1435 * Bits 6:3, more than one bit can be set, fall through cases.
1436 */
1437 protocols = device_info->device_info & 0x78;
1438 identify->initiator_port_protocols = 0;
1439 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1440 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1441 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1442 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1443 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1444 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1445 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1446 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1447
1448 /*
1449 * Fill in Phy Target Port Protocol.
1450 * Bits 10:7, more than one bit can be set, fall through cases.
1451 */
1452 protocols = device_info->device_info & 0x780;
1453 identify->target_port_protocols = 0;
1454 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1455 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1456 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1457 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1458 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1459 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1460 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1461 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1462
1463 /*
1464 * Fill in Attached device type.
1465 */
1466 switch (device_info->device_info &
1467 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1468 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1469 identify->device_type = SAS_PHY_UNUSED;
1470 break;
1471 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1472 identify->device_type = SAS_END_DEVICE;
1473 break;
1474 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1475 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1476 break;
1477 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1478 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1479 break;
1480 }
1481}
1482
1483static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001484 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001485{
Moore, Erice6b2d762006-03-14 09:14:24 -07001486 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001487 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001488 struct sas_port *port;
1489 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001490
Eric Moore547f9a22006-06-27 14:42:12 -06001491 if (!dev) {
1492 error = -ENODEV;
1493 goto out;
1494 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001495
1496 if (!phy_info->phy) {
1497 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001498 if (!phy) {
1499 error = -ENOMEM;
1500 goto out;
1501 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001502 } else
1503 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001504
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001505 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001506
1507 /*
1508 * Set Negotiated link rate.
1509 */
1510 switch (phy_info->negotiated_link_rate) {
1511 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001512 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001513 break;
1514 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001515 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001516 break;
1517 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001518 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001519 break;
1520 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001521 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001522 break;
1523 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1524 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1525 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001526 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001527 break;
1528 }
1529
1530 /*
1531 * Set Max hardware link rate.
1532 */
1533 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1534 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001535 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001536 break;
1537 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001538 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001539 break;
1540 default:
1541 break;
1542 }
1543
1544 /*
1545 * Set Max programmed link rate.
1546 */
1547 switch (phy_info->programmed_link_rate &
1548 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1549 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001550 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001551 break;
1552 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001553 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001554 break;
1555 default:
1556 break;
1557 }
1558
1559 /*
1560 * Set Min hardware link rate.
1561 */
1562 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1563 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001564 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001565 break;
1566 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001567 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001568 break;
1569 default:
1570 break;
1571 }
1572
1573 /*
1574 * Set Min programmed link rate.
1575 */
1576 switch (phy_info->programmed_link_rate &
1577 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1578 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001579 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001580 break;
1581 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001582 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001583 break;
1584 default:
1585 break;
1586 }
1587
Moore, Erice6b2d762006-03-14 09:14:24 -07001588 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001589
Moore, Erice6b2d762006-03-14 09:14:24 -07001590 if (local)
1591 phy->local_attached = 1;
1592
1593 error = sas_phy_add(phy);
1594 if (error) {
1595 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001596 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001597 }
1598 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001599 }
1600
Eric Moore547f9a22006-06-27 14:42:12 -06001601 if (!phy_info->attached.handle ||
1602 !phy_info->port_details)
1603 goto out;
1604
1605 port = mptsas_get_port(phy_info);
1606 ioc = phy_to_ioc(phy_info->phy);
1607
1608 if (phy_info->sas_port_add_phy) {
1609
1610 if (!port) {
1611 port = sas_port_alloc(dev,
1612 phy_info->port_details->port_id);
1613 dsaswideprintk((KERN_DEBUG
1614 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1615 port, dev, phy_info->port_details->port_id));
1616 if (!port) {
1617 error = -ENOMEM;
1618 goto out;
1619 }
1620 error = sas_port_add(port);
1621 if (error) {
1622 dfailprintk((MYIOC_s_ERR_FMT
1623 "%s: exit at line=%d\n", ioc->name,
1624 __FUNCTION__, __LINE__));
1625 goto out;
1626 }
1627 mptsas_set_port(phy_info, port);
1628 }
1629 dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
1630 phy_info->phy_id));
1631 sas_port_add_phy(port, phy_info->phy);
1632 phy_info->sas_port_add_phy = 0;
1633 }
1634
1635 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001636
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001637 struct sas_rphy *rphy;
James Bottomleyf013db32006-03-18 14:54:36 -06001638 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001639
Moore, Erice6b2d762006-03-14 09:14:24 -07001640 /*
1641 * Let the hotplug_work thread handle processing
1642 * the adding/removing of devices that occur
1643 * after start of day.
1644 */
1645 if (ioc->sas_discovery_runtime &&
1646 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001647 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001648
James Bottomleyf013db32006-03-18 14:54:36 -06001649 mptsas_parse_device_info(&identify, &phy_info->attached);
1650 switch (identify.device_type) {
1651 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001652 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06001653 break;
1654 case SAS_EDGE_EXPANDER_DEVICE:
1655 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001656 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06001657 break;
1658 default:
1659 rphy = NULL;
1660 break;
1661 }
Eric Moore547f9a22006-06-27 14:42:12 -06001662 if (!rphy) {
1663 dfailprintk((MYIOC_s_ERR_FMT
1664 "%s: exit at line=%d\n", ioc->name,
1665 __FUNCTION__, __LINE__));
1666 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001667 }
1668
Eric Moore547f9a22006-06-27 14:42:12 -06001669 rphy->identify = identify;
1670 error = sas_rphy_add(rphy);
1671 if (error) {
1672 dfailprintk((MYIOC_s_ERR_FMT
1673 "%s: exit at line=%d\n", ioc->name,
1674 __FUNCTION__, __LINE__));
1675 sas_rphy_free(rphy);
1676 goto out;
1677 }
1678 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001679 }
1680
Eric Moore547f9a22006-06-27 14:42:12 -06001681 out:
1682 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001683}
1684
1685static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001686mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001687{
Moore, Erice6b2d762006-03-14 09:14:24 -07001688 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001689 u32 handle = 0xFFFF;
1690 int error = -ENOMEM, i;
1691
Moore, Erice6b2d762006-03-14 09:14:24 -07001692 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1693 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001694 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001695
Moore, Erice6b2d762006-03-14 09:14:24 -07001696 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001697 if (error)
1698 goto out_free_port_info;
1699
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001700 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001701 port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
1702 if (!port_info) {
1703 port_info = hba;
1704 list_add_tail(&port_info->list, &ioc->sas_topology);
1705 } else {
1706 port_info->handle = hba->handle;
1707 for (i = 0; i < hba->num_phys; i++)
1708 port_info->phy_info[i].negotiated_link_rate =
1709 hba->phy_info[i].negotiated_link_rate;
Eric Moore547f9a22006-06-27 14:42:12 -06001710 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001711 kfree(hba);
1712 hba = NULL;
1713 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001714 mutex_unlock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001715 ioc->num_ports = port_info->num_phys;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001716
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001717 for (i = 0; i < port_info->num_phys; i++) {
1718 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1719 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1720 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1721
1722 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1723 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1724 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001725 port_info->phy_info[i].identify.phy_id =
1726 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001727 handle = port_info->phy_info[i].identify.handle;
1728
Eric Moore547f9a22006-06-27 14:42:12 -06001729 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001730 mptsas_sas_device_pg0(ioc,
1731 &port_info->phy_info[i].attached,
1732 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1733 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1734 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06001735 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001736
Eric Moore547f9a22006-06-27 14:42:12 -06001737 mptsas_setup_wide_ports(ioc, port_info);
1738
1739 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001740 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07001741 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001742
1743 return 0;
1744
1745 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06001746 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001747 out:
1748 return error;
1749}
1750
1751static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001752mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001753{
Moore, Erice6b2d762006-03-14 09:14:24 -07001754 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06001755 struct device *parent;
1756 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001757 int error = -ENOMEM, i, j;
1758
Moore, Erice6b2d762006-03-14 09:14:24 -07001759 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1760 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001761 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001762
Moore, Erice6b2d762006-03-14 09:14:24 -07001763 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001764 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1765 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1766 if (error)
1767 goto out_free_port_info;
1768
Moore, Erice6b2d762006-03-14 09:14:24 -07001769 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001770
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001771 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001772 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1773 if (!port_info) {
1774 port_info = ex;
1775 list_add_tail(&port_info->list, &ioc->sas_topology);
1776 } else {
1777 port_info->handle = ex->handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001778 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001779 kfree(ex);
1780 ex = NULL;
1781 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001782 mutex_unlock(&ioc->sas_topology_mutex);
1783
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001784 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001785 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1786 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1787 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1788
1789 if (port_info->phy_info[i].identify.handle) {
1790 mptsas_sas_device_pg0(ioc,
1791 &port_info->phy_info[i].identify,
1792 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1793 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1794 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001795 port_info->phy_info[i].identify.phy_id =
1796 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001797 }
1798
1799 if (port_info->phy_info[i].attached.handle) {
1800 mptsas_sas_device_pg0(ioc,
1801 &port_info->phy_info[i].attached,
1802 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1803 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1804 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001805 port_info->phy_info[i].attached.phy_id =
1806 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001807 }
Eric Moore547f9a22006-06-27 14:42:12 -06001808 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001809
Eric Moore547f9a22006-06-27 14:42:12 -06001810 parent = &ioc->sh->shost_gendev;
1811 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001812 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001813 list_for_each_entry(p, &ioc->sas_topology, list) {
1814 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001815 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001816 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06001817 continue;
1818 rphy = mptsas_get_rphy(&p->phy_info[j]);
1819 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001820 }
1821 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001822 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001823 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moore547f9a22006-06-27 14:42:12 -06001825 mptsas_setup_wide_ports(ioc, port_info);
1826
1827 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001828 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001829 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001830
1831 return 0;
1832
1833 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001834 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06001835 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001836 kfree(ex);
1837 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838 out:
1839 return error;
1840}
1841
Moore, Erice6b2d762006-03-14 09:14:24 -07001842/*
1843 * mptsas_delete_expander_phys
1844 *
1845 *
1846 * This will traverse topology, and remove expanders
1847 * that are no longer present
1848 */
1849static void
1850mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1851{
1852 struct mptsas_portinfo buffer;
1853 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06001854 struct mptsas_phyinfo *phy_info;
1855 struct scsi_target * starget;
1856 VirtTarget * vtarget;
1857 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07001858 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06001859 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07001860
1861 mutex_lock(&ioc->sas_topology_mutex);
1862 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1863
1864 if (port_info->phy_info &&
1865 (!(port_info->phy_info[0].identify.device_info &
1866 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1867 continue;
1868
1869 if (mptsas_sas_expander_pg0(ioc, &buffer,
1870 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1871 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1872
1873 /*
Eric Moore547f9a22006-06-27 14:42:12 -06001874 * Issue target reset to all child end devices
1875 * then mark them deleted to prevent further
1876 * IO going to them.
1877 */
1878 phy_info = port_info->phy_info;
1879 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
1880 starget = mptsas_get_starget(phy_info);
1881 if (!starget)
1882 continue;
1883 vtarget = starget->hostdata;
1884 if(vtarget->deleted)
1885 continue;
1886 vtarget->deleted = 1;
1887 mptsas_target_reset(ioc, vtarget);
1888 sas_port_delete(mptsas_get_port(phy_info));
1889 mptsas_port_delete(phy_info->port_details);
1890 }
1891
1892 /*
Moore, Erice6b2d762006-03-14 09:14:24 -07001893 * Obtain the port_info instance to the parent port
1894 */
1895 parent = mptsas_find_portinfo_by_handle(ioc,
1896 port_info->phy_info[0].identify.handle_parent);
1897
1898 if (!parent)
1899 goto next_port;
1900
Eric Moore547f9a22006-06-27 14:42:12 -06001901 expander_sas_address =
1902 port_info->phy_info[0].identify.sas_address;
1903
Moore, Erice6b2d762006-03-14 09:14:24 -07001904 /*
1905 * Delete rphys in the parent that point
1906 * to this expander. The transport layer will
1907 * cleanup all the children.
1908 */
Eric Moore547f9a22006-06-27 14:42:12 -06001909 phy_info = parent->phy_info;
1910 for (i = 0; i < parent->num_phys; i++, phy_info++) {
1911 port = mptsas_get_port(phy_info);
1912 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07001913 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06001914 if (phy_info->attached.sas_address !=
1915 expander_sas_address)
1916 continue;
1917#ifdef MPT_DEBUG_SAS_WIDE
1918 dev_printk(KERN_DEBUG, &port->dev, "delete\n");
1919#endif
1920 sas_port_delete(port);
1921 mptsas_port_delete(phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07001922 }
1923 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06001924
1925 phy_info = port_info->phy_info;
1926 for (i = 0; i < port_info->num_phys; i++, phy_info++)
1927 mptsas_port_delete(phy_info->port_details);
1928
Moore, Erice6b2d762006-03-14 09:14:24 -07001929 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06001930 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001931 kfree(port_info);
1932 }
1933 /*
1934 * Free this memory allocated from inside
1935 * mptsas_sas_expander_pg0
1936 */
Eric Moore547f9a22006-06-27 14:42:12 -06001937 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001938 }
1939 mutex_unlock(&ioc->sas_topology_mutex);
1940}
1941
1942/*
1943 * Start of day discovery
1944 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001945static void
1946mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1947{
1948 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001949 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001950
Moore, Erice6b2d762006-03-14 09:14:24 -07001951 mutex_lock(&ioc->sas_discovery_mutex);
1952 mptsas_probe_hba_phys(ioc);
1953 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001954 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001955 /*
1956 Reporting RAID volumes.
1957 */
1958 if (!ioc->raid_data.pIocPg2)
1959 goto out;
1960 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1961 goto out;
1962 for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1963 scsi_add_device(ioc->sh, ioc->num_ports,
1964 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
1965 }
1966 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07001967 mutex_unlock(&ioc->sas_discovery_mutex);
1968}
1969
1970/*
1971 * Work queue thread to handle Runtime discovery
1972 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06001973 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07001974 */
1975static void
Eric Moore547f9a22006-06-27 14:42:12 -06001976__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07001977{
Moore, Erice6b2d762006-03-14 09:14:24 -07001978 u32 handle = 0xFFFF;
1979
Moore, Erice6b2d762006-03-14 09:14:24 -07001980 ioc->sas_discovery_runtime=1;
1981 mptsas_delete_expander_phys(ioc);
1982 mptsas_probe_hba_phys(ioc);
1983 while (!mptsas_probe_expander_phys(ioc, &handle))
1984 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07001985 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06001986}
1987
1988/*
1989 * Work queue thread to handle Runtime discovery
1990 * Mere purpose is the hot add/delete of expanders
1991 *(Mutex LOCKED)
1992 */
1993static void
1994mptsas_discovery_work(void * arg)
1995{
1996 struct mptsas_discovery_event *ev = arg;
1997 MPT_ADAPTER *ioc = ev->ioc;
1998
1999 mutex_lock(&ioc->sas_discovery_mutex);
2000 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002001 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002002 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002003}
2004
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002005static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002006mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002007{
2008 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002009 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002010 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002011
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002012 mutex_lock(&ioc->sas_topology_mutex);
2013 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2014 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002015 if (port_info->phy_info[i].attached.sas_address
2016 != sas_address)
2017 continue;
2018 if (!mptsas_is_end_device(
2019 &port_info->phy_info[i].attached))
2020 continue;
2021 phy_info = &port_info->phy_info[i];
2022 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002023 }
2024 }
2025 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002026 return phy_info;
2027}
2028
2029static struct mptsas_phyinfo *
Moore, Ericc73787ee2006-01-26 16:20:06 -07002030mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002031{
2032 struct mptsas_portinfo *port_info;
2033 struct mptsas_phyinfo *phy_info = NULL;
2034 int i;
2035
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002036 mutex_lock(&ioc->sas_topology_mutex);
2037 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002038 for (i = 0; i < port_info->num_phys; i++) {
2039 if (port_info->phy_info[i].attached.id != id)
2040 continue;
2041 if (!mptsas_is_end_device(
2042 &port_info->phy_info[i].attached))
2043 continue;
2044 phy_info = &port_info->phy_info[i];
2045 break;
2046 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002047 }
2048 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002049 return phy_info;
2050}
2051
Moore, Eric4b766472006-03-14 09:14:12 -07002052/*
2053 * Work queue thread to clear the persitency table
2054 */
2055static void
Eric Moore547f9a22006-06-27 14:42:12 -06002056mptsas_persist_clear_table(void * arg)
Moore, Eric4b766472006-03-14 09:14:12 -07002057{
2058 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
2059
2060 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2061}
2062
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002063static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002064mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2065{
2066 sdev->no_uld_attach = data ? 1 : 0;
2067 scsi_device_reprobe(sdev);
2068}
2069
2070static void
2071mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2072{
2073 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2074 mptsas_reprobe_lun);
2075}
2076
Moore, Erice6b2d762006-03-14 09:14:24 -07002077/*
2078 * Work queue thread to handle SAS hotplug events
2079 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002080static void
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002081mptsas_hotplug_work(void *arg)
2082{
2083 struct mptsas_hotplug_event *ev = arg;
2084 MPT_ADAPTER *ioc = ev->ioc;
2085 struct mptsas_phyinfo *phy_info;
2086 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002087 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002088 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002089 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002090 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002091 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002092 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002093 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002094 VirtDevice *vdevice;
2095
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002096
Moore, Erice6b2d762006-03-14 09:14:24 -07002097 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002098 switch (ev->event_type) {
2099 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002100
Moore, Ericc73787ee2006-01-26 16:20:06 -07002101 phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002102
Moore, Ericf44e5462006-03-14 09:14:21 -07002103 /*
2104 * Sanity checks, for non-existing phys and remote rphys.
2105 */
Eric Moore547f9a22006-06-27 14:42:12 -06002106 if (!phy_info || !phy_info->port_details) {
2107 dfailprintk((MYIOC_s_ERR_FMT
2108 "%s: exit at line=%d\n", ioc->name,
2109 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002110 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002111 }
2112 rphy = mptsas_get_rphy(phy_info);
2113 if (!rphy) {
2114 dfailprintk((MYIOC_s_ERR_FMT
2115 "%s: exit at line=%d\n", ioc->name,
2116 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002117 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002118 }
2119 port = mptsas_get_port(phy_info);
2120 if (!port) {
2121 dfailprintk((MYIOC_s_ERR_FMT
2122 "%s: exit at line=%d\n", ioc->name,
2123 __FUNCTION__, __LINE__));
2124 break;
2125 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002126
Eric Moore547f9a22006-06-27 14:42:12 -06002127 starget = mptsas_get_starget(phy_info);
2128 if (starget) {
2129 vtarget = starget->hostdata;
2130
2131 if (!vtarget) {
2132 dfailprintk((MYIOC_s_ERR_FMT
2133 "%s: exit at line=%d\n", ioc->name,
2134 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002135 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002136 }
2137
Moore, Ericf44e5462006-03-14 09:14:21 -07002138 /*
2139 * Handling RAID components
2140 */
2141 if (ev->phys_disk_num_valid) {
2142 vtarget->target_id = ev->phys_disk_num;
2143 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002144 mptsas_reprobe_target(starget, 1);
Moore, Ericf44e5462006-03-14 09:14:21 -07002145 break;
2146 }
Eric Moore547f9a22006-06-27 14:42:12 -06002147
2148 vtarget->deleted = 1;
2149 mptsas_target_reset(ioc, vtarget);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002150 }
2151
Moore, Ericc73787ee2006-01-26 16:20:06 -07002152 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2153 ds = "ssp";
2154 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
2155 ds = "stp";
2156 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2157 ds = "sata";
2158
2159 printk(MYIOC_s_INFO_FMT
2160 "removing %s device, channel %d, id %d, phy %d\n",
2161 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
2162
Eric Moore547f9a22006-06-27 14:42:12 -06002163#ifdef MPT_DEBUG_SAS_WIDE
2164 dev_printk(KERN_DEBUG, &port->dev, "delete\n");
2165#endif
2166 sas_port_delete(port);
2167 mptsas_port_delete(phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002168 break;
2169 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002170
Moore, Ericbd23e942006-04-17 12:43:04 -06002171 if (ev->phys_disk_num_valid)
2172 mpt_findImVolumes(ioc);
2173
Moore, Ericc73787ee2006-01-26 16:20:06 -07002174 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002175 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002176 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002177 if (mptsas_sas_device_pg0(ioc, &sas_device,
2178 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Moore547f9a22006-06-27 14:42:12 -06002179 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) {
2180 dfailprintk((MYIOC_s_ERR_FMT
2181 "%s: exit at line=%d\n", ioc->name,
2182 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002183 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002184 }
2185
Eric Moore547f9a22006-06-27 14:42:12 -06002186 ssleep(2);
2187 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002188
Eric Moore547f9a22006-06-27 14:42:12 -06002189 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2190 sas_device.sas_address);
2191
2192 if (!phy_info || !phy_info->port_details) {
2193 dfailprintk((MYIOC_s_ERR_FMT
2194 "%s: exit at line=%d\n", ioc->name,
2195 __FUNCTION__, __LINE__));
2196 break;
2197 }
2198
2199 starget = mptsas_get_starget(phy_info);
2200 if (starget) {
2201 vtarget = starget->hostdata;
2202
2203 if (!vtarget) {
2204 dfailprintk((MYIOC_s_ERR_FMT
2205 "%s: exit at line=%d\n", ioc->name,
2206 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002207 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002208 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002209 /*
2210 * Handling RAID components
2211 */
2212 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
2213 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
2214 vtarget->target_id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002215 mptsas_reprobe_target(starget, 0);
Moore, Ericf44e5462006-03-14 09:14:21 -07002216 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002217 break;
2218 }
2219
Eric Moore547f9a22006-06-27 14:42:12 -06002220 if (mptsas_get_rphy(phy_info)) {
2221 dfailprintk((MYIOC_s_ERR_FMT
2222 "%s: exit at line=%d\n", ioc->name,
2223 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002224 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002225 }
2226 port = mptsas_get_port(phy_info);
2227 if (!port) {
2228 dfailprintk((MYIOC_s_ERR_FMT
2229 "%s: exit at line=%d\n", ioc->name,
2230 __FUNCTION__, __LINE__));
2231 break;
2232 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002233
Christoph Hellwige3094442006-02-16 13:25:36 +01002234 memcpy(&phy_info->attached, &sas_device,
2235 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002236
Moore, Ericc73787ee2006-01-26 16:20:06 -07002237 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2238 ds = "ssp";
2239 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
2240 ds = "stp";
2241 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2242 ds = "sata";
2243
2244 printk(MYIOC_s_INFO_FMT
2245 "attaching %s device, channel %d, id %d, phy %d\n",
2246 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2247
James Bottomleyf013db32006-03-18 14:54:36 -06002248 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002249 rphy = sas_end_device_alloc(port);
2250 if (!rphy) {
2251 dfailprintk((MYIOC_s_ERR_FMT
2252 "%s: exit at line=%d\n", ioc->name,
2253 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002254 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002255 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002256
James Bottomleyf013db32006-03-18 14:54:36 -06002257 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002258 if (sas_rphy_add(rphy)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002259 dfailprintk((MYIOC_s_ERR_FMT
2260 "%s: exit at line=%d\n", ioc->name,
2261 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002262 sas_rphy_free(rphy);
2263 break;
2264 }
Eric Moore547f9a22006-06-27 14:42:12 -06002265 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002266 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002267 case MPTSAS_ADD_RAID:
2268 sdev = scsi_device_lookup(
2269 ioc->sh,
2270 ioc->num_ports,
2271 ev->id,
2272 0);
2273 if (sdev) {
2274 scsi_device_put(sdev);
2275 break;
2276 }
2277 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002278 "attaching raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07002279 ioc->name, ioc->num_ports, ev->id);
2280 scsi_add_device(ioc->sh,
2281 ioc->num_ports,
2282 ev->id,
2283 0);
2284 mpt_findImVolumes(ioc);
2285 break;
2286 case MPTSAS_DEL_RAID:
2287 sdev = scsi_device_lookup(
2288 ioc->sh,
2289 ioc->num_ports,
2290 ev->id,
2291 0);
2292 if (!sdev)
2293 break;
2294 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002295 "removing raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07002296 ioc->name, ioc->num_ports, ev->id);
Eric Moore547f9a22006-06-27 14:42:12 -06002297 vdevice = sdev->hostdata;
2298 vdevice->vtarget->deleted = 1;
2299 mptsas_target_reset(ioc, vdevice->vtarget);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002300 scsi_remove_device(sdev);
2301 scsi_device_put(sdev);
2302 mpt_findImVolumes(ioc);
2303 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002304 case MPTSAS_IGNORE_EVENT:
2305 default:
2306 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002307 }
2308
Moore, Erice6b2d762006-03-14 09:14:24 -07002309 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002310 kfree(ev);
2311
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002312}
2313
2314static void
Eric Moore547f9a22006-06-27 14:42:12 -06002315mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002316 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2317{
2318 struct mptsas_hotplug_event *ev;
2319 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2320 __le64 sas_address;
2321
2322 if ((device_info &
2323 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2324 MPI_SAS_DEVICE_INFO_STP_TARGET |
2325 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2326 return;
2327
Moore, Eric4b766472006-03-14 09:14:12 -07002328 switch (sas_event_data->ReasonCode) {
2329 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
2330 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore547f9a22006-06-27 14:42:12 -06002331 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002332 if (!ev) {
2333 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2334 break;
2335 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002336
Moore, Eric4b766472006-03-14 09:14:12 -07002337 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
2338 ev->ioc = ioc;
2339 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2340 ev->parent_handle =
2341 le16_to_cpu(sas_event_data->ParentDevHandle);
2342 ev->channel = sas_event_data->Bus;
2343 ev->id = sas_event_data->TargetID;
2344 ev->phy_id = sas_event_data->PhyNum;
2345 memcpy(&sas_address, &sas_event_data->SASAddress,
2346 sizeof(__le64));
2347 ev->sas_address = le64_to_cpu(sas_address);
2348 ev->device_info = device_info;
2349
2350 if (sas_event_data->ReasonCode &
2351 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2352 ev->event_type = MPTSAS_ADD_DEVICE;
2353 else
2354 ev->event_type = MPTSAS_DEL_DEVICE;
2355 schedule_work(&ev->work);
2356 break;
2357 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2358 /*
2359 * Persistent table is full.
2360 */
Eric Moore547f9a22006-06-27 14:42:12 -06002361 INIT_WORK(&ioc->sas_persist_task,
2362 mptsas_persist_clear_table, (void *)ioc);
2363 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002364 break;
2365 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
2366 /* TODO */
2367 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
2368 /* TODO */
2369 default:
2370 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002371 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002372}
2373
Moore, Ericc73787ee2006-01-26 16:20:06 -07002374static void
Eric Moore547f9a22006-06-27 14:42:12 -06002375mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002376 EVENT_DATA_RAID *raid_event_data)
2377{
2378 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002379 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2380 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002381
2382 if (ioc->bus_type != SAS)
2383 return;
2384
Eric Moore547f9a22006-06-27 14:42:12 -06002385 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002386 if (!ev) {
2387 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2388 return;
2389 }
2390
Moore, Ericc73787ee2006-01-26 16:20:06 -07002391 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
2392 ev->ioc = ioc;
2393 ev->id = raid_event_data->VolumeID;
Moore, Ericbd23e942006-04-17 12:43:04 -06002394 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002395
2396 switch (raid_event_data->ReasonCode) {
2397 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
2398 ev->event_type = MPTSAS_ADD_DEVICE;
2399 break;
2400 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002401 ioc->raid_data.isRaid = 1;
2402 ev->phys_disk_num_valid = 1;
2403 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002404 ev->event_type = MPTSAS_DEL_DEVICE;
2405 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002406 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2407 switch (state) {
2408 case MPI_PD_STATE_ONLINE:
2409 ioc->raid_data.isRaid = 1;
2410 ev->phys_disk_num_valid = 1;
2411 ev->phys_disk_num = raid_event_data->PhysDiskNum;
2412 ev->event_type = MPTSAS_ADD_DEVICE;
2413 break;
2414 case MPI_PD_STATE_MISSING:
2415 case MPI_PD_STATE_NOT_COMPATIBLE:
2416 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2417 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2418 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
2419 ev->event_type = MPTSAS_DEL_DEVICE;
2420 break;
2421 default:
2422 break;
2423 }
2424 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002425 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2426 ev->event_type = MPTSAS_DEL_RAID;
2427 break;
2428 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2429 ev->event_type = MPTSAS_ADD_RAID;
2430 break;
2431 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002432 switch (state) {
2433 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2434 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2435 ev->event_type = MPTSAS_DEL_RAID;
2436 break;
2437 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2438 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2439 ev->event_type = MPTSAS_ADD_RAID;
2440 break;
2441 default:
2442 break;
2443 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002444 break;
2445 default:
2446 break;
2447 }
2448 schedule_work(&ev->work);
2449}
2450
Moore, Erice6b2d762006-03-14 09:14:24 -07002451static void
Eric Moore547f9a22006-06-27 14:42:12 -06002452mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002453 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2454{
2455 struct mptsas_discovery_event *ev;
2456
2457 /*
2458 * DiscoveryStatus
2459 *
2460 * This flag will be non-zero when firmware
2461 * kicks off discovery, and return to zero
2462 * once its completed.
2463 */
2464 if (discovery_data->DiscoveryStatus)
2465 return;
2466
Eric Moore547f9a22006-06-27 14:42:12 -06002467 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002468 if (!ev)
2469 return;
Eric Moore547f9a22006-06-27 14:42:12 -06002470 INIT_WORK(&ev->work, mptsas_discovery_work, ev);
Moore, Erice6b2d762006-03-14 09:14:24 -07002471 ev->ioc = ioc;
2472 schedule_work(&ev->work);
2473};
2474
2475
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002476static int
2477mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2478{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002479 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002480 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2481
2482 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002483 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002484
Moore, Erice6b2d762006-03-14 09:14:24 -07002485 /*
2486 * sas_discovery_ignore_events
2487 *
2488 * This flag is to prevent anymore processing of
2489 * sas events once mptsas_remove function is called.
2490 */
2491 if (ioc->sas_discovery_ignore_events) {
2492 rc = mptscsih_event_process(ioc, reply);
2493 goto out;
2494 }
2495
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002496 switch (event) {
2497 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06002498 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002499 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002500 break;
2501 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06002502 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002503 (EVENT_DATA_RAID *)reply->Data);
2504 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002505 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06002506 INIT_WORK(&ioc->sas_persist_task,
2507 mptsas_persist_clear_table,
Moore, Eric79de2782006-01-25 18:05:15 -07002508 (void *)ioc);
Eric Moore547f9a22006-06-27 14:42:12 -06002509 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07002510 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002511 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06002512 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002513 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2514 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002515 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002516 rc = mptscsih_event_process(ioc, reply);
2517 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002518 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002519 out:
2520
2521 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002522}
2523
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002524static int
2525mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2526{
2527 struct Scsi_Host *sh;
2528 MPT_SCSI_HOST *hd;
2529 MPT_ADAPTER *ioc;
2530 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002531 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002532 int numSGE = 0;
2533 int scale;
2534 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002535 int error=0;
2536 int r;
2537
2538 r = mpt_attach(pdev,id);
2539 if (r)
2540 return r;
2541
2542 ioc = pci_get_drvdata(pdev);
2543 ioc->DoneCtx = mptsasDoneCtx;
2544 ioc->TaskCtx = mptsasTaskCtx;
2545 ioc->InternalCtx = mptsasInternalCtx;
2546
2547 /* Added sanity check on readiness of the MPT adapter.
2548 */
2549 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2550 printk(MYIOC_s_WARN_FMT
2551 "Skipping because it's not operational!\n",
2552 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002553 error = -ENODEV;
2554 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002555 }
2556
2557 if (!ioc->active) {
2558 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2559 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002560 error = -ENODEV;
2561 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002562 }
2563
2564 /* Sanity check - ensure at least 1 port is INITIATOR capable
2565 */
2566 ioc_cap = 0;
2567 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2568 if (ioc->pfacts[ii].ProtocolFlags &
2569 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2570 ioc_cap++;
2571 }
2572
2573 if (!ioc_cap) {
2574 printk(MYIOC_s_WARN_FMT
2575 "Skipping ioc=%p because SCSI Initiator mode "
2576 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002577 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002578 }
2579
2580 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2581 if (!sh) {
2582 printk(MYIOC_s_WARN_FMT
2583 "Unable to register controller with SCSI subsystem\n",
2584 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002585 error = -1;
2586 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002587 }
2588
2589 spin_lock_irqsave(&ioc->FreeQlock, flags);
2590
2591 /* Attach the SCSI Host to the IOC structure
2592 */
2593 ioc->sh = sh;
2594
2595 sh->io_port = 0;
2596 sh->n_io_port = 0;
2597 sh->irq = 0;
2598
2599 /* set 16 byte cdb's */
2600 sh->max_cmd_len = 16;
2601
2602 sh->max_id = ioc->pfacts->MaxDevices + 1;
2603
2604 sh->transportt = mptsas_transport_template;
2605
2606 sh->max_lun = MPT_LAST_LUN + 1;
2607 sh->max_channel = 0;
2608 sh->this_id = ioc->pfacts[0].PortSCSIID;
2609
2610 /* Required entry.
2611 */
2612 sh->unique_id = ioc->id;
2613
2614 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002615 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002616 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002617 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002618 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002619
2620 /* Verify that we won't exceed the maximum
2621 * number of chain buffers
2622 * We can optimize: ZZ = req_sz/sizeof(SGE)
2623 * For 32bit SGE's:
2624 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2625 * + (req_sz - 64)/sizeof(SGE)
2626 * A slightly different algorithm is required for
2627 * 64bit SGEs.
2628 */
2629 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2630 if (sizeof(dma_addr_t) == sizeof(u64)) {
2631 numSGE = (scale - 1) *
2632 (ioc->facts.MaxChainDepth-1) + scale +
2633 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2634 sizeof(u32));
2635 } else {
2636 numSGE = 1 + (scale - 1) *
2637 (ioc->facts.MaxChainDepth-1) + scale +
2638 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2639 sizeof(u32));
2640 }
2641
2642 if (numSGE < sh->sg_tablesize) {
2643 /* Reset this value */
2644 dprintk((MYIOC_s_INFO_FMT
2645 "Resetting sg_tablesize to %d from %d\n",
2646 ioc->name, numSGE, sh->sg_tablesize));
2647 sh->sg_tablesize = numSGE;
2648 }
2649
2650 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2651
2652 hd = (MPT_SCSI_HOST *) sh->hostdata;
2653 hd->ioc = ioc;
2654
2655 /* SCSI needs scsi_cmnd lookup table!
2656 * (with size equal to req_depth*PtrSz!)
2657 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002658 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2659 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002660 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002661 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002662 }
2663
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002664 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2665 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002666
2667 /* Allocate memory for the device structures.
2668 * A non-Null pointer at an offset
2669 * indicates a device exists.
2670 * max_id = 1 + maximum id (hosts.h)
2671 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002672 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
2673 if (!hd->Targets) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002674 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002675 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002676 }
2677
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002678 dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002679
2680 /* Clear the TM flags
2681 */
2682 hd->tmPending = 0;
2683 hd->tmState = TM_STATE_NONE;
2684 hd->resetPending = 0;
2685 hd->abortSCpnt = NULL;
2686
2687 /* Clear the pointer used to store
2688 * single-threaded commands, i.e., those
2689 * issued during a bus scan, dv and
2690 * configuration pages.
2691 */
2692 hd->cmdPtr = NULL;
2693
2694 /* Initialize this SCSI Hosts' timers
2695 * To use, set the timer expires field
2696 * and add_timer
2697 */
2698 init_timer(&hd->timer);
2699 hd->timer.data = (unsigned long) hd;
2700 hd->timer.function = mptscsih_timer_expired;
2701
2702 hd->mpt_pq_filter = mpt_pq_filter;
2703 ioc->sas_data.ptClear = mpt_pt_clear;
2704
2705 if (ioc->sas_data.ptClear==1) {
2706 mptbase_sas_persist_operation(
2707 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2708 }
2709
2710 ddvprintk((MYIOC_s_INFO_FMT
2711 "mpt_pq_filter %x mpt_pq_filter %x\n",
2712 ioc->name,
2713 mpt_pq_filter,
2714 mpt_pq_filter));
2715
2716 init_waitqueue_head(&hd->scandv_waitq);
2717 hd->scandv_wait_done = 0;
2718 hd->last_queue_full = 0;
2719
2720 error = scsi_add_host(sh, &ioc->pcidev->dev);
2721 if (error) {
2722 dprintk((KERN_ERR MYNAM
2723 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002724 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002725 }
2726
2727 mptsas_scan_sas_topology(ioc);
2728
2729 return 0;
2730
Eric Moore547f9a22006-06-27 14:42:12 -06002731 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002732
2733 mptscsih_remove(pdev);
2734 return error;
2735}
2736
2737static void __devexit mptsas_remove(struct pci_dev *pdev)
2738{
2739 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2740 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06002741 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002742
Moore, Erice6b2d762006-03-14 09:14:24 -07002743 ioc->sas_discovery_ignore_events=1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002744 sas_remove_host(ioc->sh);
2745
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002746 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002747 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2748 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002749 for (i = 0 ; i < p->num_phys ; i++)
2750 mptsas_port_delete(p->phy_info[i].port_details);
2751 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002752 kfree(p);
2753 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002754 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002755
2756 mptscsih_remove(pdev);
2757}
2758
2759static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06002760 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002761 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002762 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002763 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002764 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002765 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002766 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002767 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002768 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002769 PCI_ANY_ID, PCI_ANY_ID },
2770 {0} /* Terminating entry */
2771};
2772MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2773
2774
2775static struct pci_driver mptsas_driver = {
2776 .name = "mptsas",
2777 .id_table = mptsas_pci_table,
2778 .probe = mptsas_probe,
2779 .remove = __devexit_p(mptsas_remove),
2780 .shutdown = mptscsih_shutdown,
2781#ifdef CONFIG_PM
2782 .suspend = mptscsih_suspend,
2783 .resume = mptscsih_resume,
2784#endif
2785};
2786
2787static int __init
2788mptsas_init(void)
2789{
2790 show_mptmod_ver(my_NAME, my_VERSION);
2791
2792 mptsas_transport_template =
2793 sas_attach_transport(&mptsas_transport_functions);
2794 if (!mptsas_transport_template)
2795 return -ENODEV;
2796
2797 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
2798 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
2799 mptsasInternalCtx =
2800 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002801 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002802
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002803 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07002804 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002805 ": Registered for IOC event notifications\n"));
2806 }
2807
2808 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
2809 dprintk((KERN_INFO MYNAM
2810 ": Registered for IOC reset notifications\n"));
2811 }
2812
2813 return pci_register_driver(&mptsas_driver);
2814}
2815
2816static void __exit
2817mptsas_exit(void)
2818{
2819 pci_unregister_driver(&mptsas_driver);
2820 sas_release_transport(mptsas_transport_template);
2821
2822 mpt_reset_deregister(mptsasDoneCtx);
2823 mpt_event_deregister(mptsasDoneCtx);
2824
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002825 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002826 mpt_deregister(mptsasInternalCtx);
2827 mpt_deregister(mptsasTaskCtx);
2828 mpt_deregister(mptsasDoneCtx);
2829}
2830
2831module_init(mptsas_init);
2832module_exit(mptsas_exit);