blob: a8df06c422bd41693f2275dc2505b135022a5f08 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic Corporation
Christoph Hellwig0c33b272005-09-09 16:27:19 +02007 * (mailto:mpt_linux_developer@lsil.com)
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 2005-2007 Dell
Christoph Hellwig0c33b272005-09-09 16:27:19 +02009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
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
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Christoph Hellwig0c33b272005-09-09 16:27:19 +020092static int mptsasDoneCtx = -1;
93static int mptsasTaskCtx = -1;
94static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020095static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020096
Eric Mooreb506ade2007-01-29 09:45:37 -070097static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Christoph Hellwig9a28f492006-01-13 18:04:41 +010099enum mptsas_hotplug_action {
100 MPTSAS_ADD_DEVICE,
101 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -0700102 MPTSAS_ADD_RAID,
103 MPTSAS_DEL_RAID,
Eric Mooreb506ade2007-01-29 09:45:37 -0700104 MPTSAS_ADD_INACTIVE_VOLUME,
Moore, Ericbd23e942006-04-17 12:43:04 -0600105 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100106};
107
108struct mptsas_hotplug_event {
109 struct work_struct work;
110 MPT_ADAPTER *ioc;
111 enum mptsas_hotplug_action event_type;
112 u64 sas_address;
Eric Mooreb506ade2007-01-29 09:45:37 -0700113 u8 channel;
114 u8 id;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100115 u32 device_info;
116 u16 handle;
117 u16 parent_handle;
118 u8 phy_id;
Eric Mooreb506ade2007-01-29 09:45:37 -0700119 u8 phys_disk_num_valid; /* hrc (hidden raid component) */
120 u8 phys_disk_num; /* hrc - unique index*/
121 u8 hidden_raid_component; /* hrc - don't expose*/
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100122};
123
Moore, Erice6b2d762006-03-14 09:14:24 -0700124struct mptsas_discovery_event {
125 struct work_struct work;
126 MPT_ADAPTER *ioc;
127};
128
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200129/*
130 * SAS topology structures
131 *
132 * The MPT Fusion firmware interface spreads information about the
133 * SAS topology over many manufacture pages, thus we need some data
134 * structure to collect it and process it for the SAS transport class.
135 */
136
137struct mptsas_devinfo {
138 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700139 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100140 u16 handle_enclosure; /* enclosure identifier of the enclosure */
141 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200142 u8 phy_id; /* phy number of parent device */
143 u8 port_id; /* sas physical port this device
144 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100145 u8 id; /* logical target id of this device */
Eric Mooreb506ade2007-01-29 09:45:37 -0700146 u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100147 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200148 u64 sas_address; /* WWN of this device,
149 SATA is assigned by HBA,expander */
150 u32 device_info; /* bitfield detailed info about this device */
151};
152
Eric Moore547f9a22006-06-27 14:42:12 -0600153/*
154 * Specific details on ports, wide/narrow
155 */
156struct mptsas_portinfo_details{
Eric Moore547f9a22006-06-27 14:42:12 -0600157 u16 num_phys; /* number of phys belong to this port */
158 u64 phy_bitmask; /* TODO, extend support for 255 phys */
159 struct sas_rphy *rphy; /* transport layer rphy object */
160 struct sas_port *port; /* transport layer port object */
161 struct scsi_target *starget;
162 struct mptsas_portinfo *port_info;
163};
164
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200165struct mptsas_phyinfo {
166 u8 phy_id; /* phy index */
Eric Moore547f9a22006-06-27 14:42:12 -0600167 u8 port_id; /* firmware port identifier */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200168 u8 negotiated_link_rate; /* nego'd link rate for this phy */
169 u8 hw_link_rate; /* hardware max/min phys link rate */
170 u8 programmed_link_rate; /* programmed max/min phy link rate */
Eric Moore547f9a22006-06-27 14:42:12 -0600171 u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200172 struct mptsas_devinfo identify; /* point to phy device info */
173 struct mptsas_devinfo attached; /* point to attached device info */
Eric Moore547f9a22006-06-27 14:42:12 -0600174 struct sas_phy *phy; /* transport layer phy object */
175 struct mptsas_portinfo *portinfo;
176 struct mptsas_portinfo_details * port_details;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200177};
178
179struct mptsas_portinfo {
180 struct list_head list;
181 u16 handle; /* unique id to address this */
Eric Moore547f9a22006-06-27 14:42:12 -0600182 u16 num_phys; /* number of phys */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200183 struct mptsas_phyinfo *phy_info;
184};
185
Christoph Hellwige3094442006-02-16 13:25:36 +0100186struct mptsas_enclosure {
187 u64 enclosure_logical_id; /* The WWN for the enclosure */
188 u16 enclosure_handle; /* unique id to address this */
189 u16 flags; /* details enclosure management */
190 u16 num_slot; /* num slots */
191 u16 start_slot; /* first slot */
192 u8 start_id; /* starting logical target id */
193 u8 start_channel; /* starting logical channel id */
194 u8 sep_id; /* SEP device logical target id */
195 u8 sep_channel; /* SEP channel logical channel id */
196};
197
Eric Moore547f9a22006-06-27 14:42:12 -0600198#ifdef MPT_DEBUG_SAS
Christoph Hellwigb5141122005-10-28 22:07:41 +0200199static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
200{
201 printk("---- IO UNIT PAGE 0 ------------\n");
202 printk("Handle=0x%X\n",
203 le16_to_cpu(phy_data->AttachedDeviceHandle));
204 printk("Controller Handle=0x%X\n",
205 le16_to_cpu(phy_data->ControllerDevHandle));
206 printk("Port=0x%X\n", phy_data->Port);
207 printk("Port Flags=0x%X\n", phy_data->PortFlags);
208 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
209 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
210 printk("Controller PHY Device Info=0x%X\n",
211 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
212 printk("DiscoveryStatus=0x%X\n",
213 le32_to_cpu(phy_data->DiscoveryStatus));
214 printk("\n");
215}
216
217static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
218{
219 __le64 sas_address;
220
221 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
222
223 printk("---- SAS PHY PAGE 0 ------------\n");
224 printk("Attached Device Handle=0x%X\n",
225 le16_to_cpu(pg0->AttachedDevHandle));
226 printk("SAS Address=0x%llX\n",
227 (unsigned long long)le64_to_cpu(sas_address));
228 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
229 printk("Attached Device Info=0x%X\n",
230 le32_to_cpu(pg0->AttachedDeviceInfo));
231 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
232 printk("Change Count=0x%X\n", pg0->ChangeCount);
233 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
234 printk("\n");
235}
236
237static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
238{
239 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200240 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
241 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200242 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200243 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
244 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
245 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200246}
247
248static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
249{
250 __le64 sas_address;
251
252 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
253
254 printk("---- SAS DEVICE PAGE 0 ---------\n");
255 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100256 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200257 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
258 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
Eric Mooref99be432007-01-04 20:46:54 -0700259 printk("SAS Address=0x%llX\n", (unsigned long long)
260 le64_to_cpu(sas_address));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200261 printk("Target ID=0x%X\n", pg0->TargetID);
262 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200263 /* The PhyNum field specifies the PHY number of the parent
264 * device this device is linked to
265 */
266 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
267 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200268 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
269 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
270 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
271 printk("\n");
272}
273
274static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
275{
276 printk("---- SAS EXPANDER PAGE 1 ------------\n");
277
278 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200279 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200280 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
281 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
282 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
283 printk("Owner Device Handle=0x%X\n",
284 le16_to_cpu(pg1->OwnerDevHandle));
285 printk("Attached Device Handle=0x%X\n",
286 le16_to_cpu(pg1->AttachedDevHandle));
287}
288#else
289#define mptsas_print_phy_data(phy_data) do { } while (0)
290#define mptsas_print_phy_pg0(pg0) do { } while (0)
291#define mptsas_print_phy_pg1(pg1) do { } while (0)
292#define mptsas_print_device_pg0(pg0) do { } while (0)
293#define mptsas_print_expander_pg1(pg1) do { } while (0)
294#endif
295
Christoph Hellwige3094442006-02-16 13:25:36 +0100296static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
297{
298 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
299 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
300}
301
302static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
303{
304 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
305 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
306}
307
Moore, Erice6b2d762006-03-14 09:14:24 -0700308/*
309 * mptsas_find_portinfo_by_handle
310 *
311 * This function should be called with the sas_topology_mutex already held
312 */
313static struct mptsas_portinfo *
314mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
315{
316 struct mptsas_portinfo *port_info, *rc=NULL;
317 int i;
318
319 list_for_each_entry(port_info, &ioc->sas_topology, list)
320 for (i = 0; i < port_info->num_phys; i++)
321 if (port_info->phy_info[i].identify.handle == handle) {
322 rc = port_info;
323 goto out;
324 }
325 out:
326 return rc;
327}
328
Moore, Ericbd23e942006-04-17 12:43:04 -0600329/*
330 * Returns true if there is a scsi end device
331 */
332static inline int
333mptsas_is_end_device(struct mptsas_devinfo * attached)
334{
Eric Moore547f9a22006-06-27 14:42:12 -0600335 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600336 (attached->device_info &
337 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
338 ((attached->device_info &
339 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
340 (attached->device_info &
341 MPI_SAS_DEVICE_INFO_STP_TARGET) |
342 (attached->device_info &
343 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
344 return 1;
345 else
346 return 0;
347}
348
Eric Moore547f9a22006-06-27 14:42:12 -0600349/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600350static void
Eric Moore547f9a22006-06-27 14:42:12 -0600351mptsas_port_delete(struct mptsas_portinfo_details * port_details)
352{
353 struct mptsas_portinfo *port_info;
354 struct mptsas_phyinfo *phy_info;
355 u8 i;
356
357 if (!port_details)
358 return;
359
360 port_info = port_details->port_info;
361 phy_info = port_info->phy_info;
362
Eric Mooredc22f162006-07-06 11:23:14 -0600363 dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700364 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
365 port_details->num_phys, (unsigned long long)
366 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600367
368 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
369 if(phy_info->port_details != port_details)
370 continue;
371 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
372 phy_info->port_details = NULL;
373 }
374 kfree(port_details);
375}
376
377static inline struct sas_rphy *
378mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
379{
380 if (phy_info->port_details)
381 return phy_info->port_details->rphy;
382 else
383 return NULL;
384}
385
386static inline void
387mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
388{
389 if (phy_info->port_details) {
390 phy_info->port_details->rphy = rphy;
391 dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
392 }
393
394#ifdef MPT_DEBUG_SAS_WIDE
395 if (rphy) {
396 dev_printk(KERN_DEBUG, &rphy->dev, "add:");
397 printk("rphy=%p release=%p\n",
398 rphy, rphy->dev.release);
399 }
400#endif
401}
402
403static inline struct sas_port *
404mptsas_get_port(struct mptsas_phyinfo *phy_info)
405{
406 if (phy_info->port_details)
407 return phy_info->port_details->port;
408 else
409 return NULL;
410}
411
412static inline void
413mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
414{
415 if (phy_info->port_details)
416 phy_info->port_details->port = port;
417
418#ifdef MPT_DEBUG_SAS_WIDE
419 if (port) {
420 dev_printk(KERN_DEBUG, &port->dev, "add: ");
421 printk("port=%p release=%p\n",
422 port, port->dev.release);
423 }
424#endif
425}
426
427static inline struct scsi_target *
428mptsas_get_starget(struct mptsas_phyinfo *phy_info)
429{
430 if (phy_info->port_details)
431 return phy_info->port_details->starget;
432 else
433 return NULL;
434}
435
436static inline void
437mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
438starget)
439{
440 if (phy_info->port_details)
441 phy_info->port_details->starget = starget;
442}
443
444
445/*
446 * mptsas_setup_wide_ports
447 *
448 * Updates for new and existing narrow/wide port configuration
449 * in the sas_topology
450 */
Eric Moore376ac832006-06-29 17:36:26 -0600451static void
Eric Moore547f9a22006-06-27 14:42:12 -0600452mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
453{
454 struct mptsas_portinfo_details * port_details;
455 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
456 u64 sas_address;
457 int i, j;
458
459 mutex_lock(&ioc->sas_topology_mutex);
460
461 phy_info = port_info->phy_info;
462 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
463 if (phy_info->attached.handle)
464 continue;
465 port_details = phy_info->port_details;
466 if (!port_details)
467 continue;
468 if (port_details->num_phys < 2)
469 continue;
470 /*
471 * Removing a phy from a port, letting the last
472 * phy be removed by firmware events.
473 */
474 dsaswideprintk((KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600475 "%s: [%p]: deleting phy = %d\n",
476 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600477 port_details->num_phys--;
478 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
479 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
480 sas_port_delete_phy(port_details->port, phy_info->phy);
481 phy_info->port_details = NULL;
482 }
483
484 /*
485 * Populate and refresh the tree
486 */
487 phy_info = port_info->phy_info;
488 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
489 sas_address = phy_info->attached.sas_address;
490 dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700491 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600492 if (!sas_address)
493 continue;
494 port_details = phy_info->port_details;
495 /*
496 * Forming a port
497 */
498 if (!port_details) {
499 port_details = kzalloc(sizeof(*port_details),
500 GFP_KERNEL);
501 if (!port_details)
502 goto out;
503 port_details->num_phys = 1;
504 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600505 if (phy_info->phy_id < 64 )
506 port_details->phy_bitmask |=
507 (1 << phy_info->phy_id);
508 phy_info->sas_port_add_phy=1;
509 dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700510 "phy_id=%d sas_address=0x%018llX\n",
511 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600512 phy_info->port_details = port_details;
513 }
514
515 if (i == port_info->num_phys - 1)
516 continue;
517 phy_info_cmp = &port_info->phy_info[i + 1];
518 for (j = i + 1 ; j < port_info->num_phys ; j++,
519 phy_info_cmp++) {
520 if (!phy_info_cmp->attached.sas_address)
521 continue;
522 if (sas_address != phy_info_cmp->attached.sas_address)
523 continue;
524 if (phy_info_cmp->port_details == port_details )
525 continue;
526 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700527 "\t\tphy_id=%d sas_address=0x%018llX\n",
528 j, (unsigned long long)
529 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600530 if (phy_info_cmp->port_details) {
531 port_details->rphy =
532 mptsas_get_rphy(phy_info_cmp);
533 port_details->port =
534 mptsas_get_port(phy_info_cmp);
535 port_details->starget =
536 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600537 port_details->num_phys =
538 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600539 if (!phy_info_cmp->port_details->num_phys)
540 kfree(phy_info_cmp->port_details);
541 } else
542 phy_info_cmp->sas_port_add_phy=1;
543 /*
544 * Adding a phy to a port
545 */
546 phy_info_cmp->port_details = port_details;
547 if (phy_info_cmp->phy_id < 64 )
548 port_details->phy_bitmask |=
549 (1 << phy_info_cmp->phy_id);
550 port_details->num_phys++;
551 }
552 }
553
554 out:
555
556#ifdef MPT_DEBUG_SAS_WIDE
557 for (i = 0; i < port_info->num_phys; i++) {
558 port_details = port_info->phy_info[i].port_details;
559 if (!port_details)
560 continue;
561 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700562 "%s: [%p]: phy_id=%02d num_phys=%02d "
563 "bitmask=0x%016llX\n", __FUNCTION__,
564 port_details, i, port_details->num_phys,
565 (unsigned long long)port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600566 dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
567 port_details->port, port_details->rphy));
568 }
569 dsaswideprintk((KERN_DEBUG"\n"));
570#endif
571 mutex_unlock(&ioc->sas_topology_mutex);
572}
573
574static void
575mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget)
576{
577 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
578
579 if (mptscsih_TMHandler(hd,
580 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Eric Moore793955f2007-01-29 09:42:20 -0700581 vtarget->channel, vtarget->id, 0, 0, 5) < 0) {
Eric Moore547f9a22006-06-27 14:42:12 -0600582 hd->tmPending = 0;
583 hd->tmState = TM_STATE_NONE;
584 printk(MYIOC_s_WARN_FMT
585 "Error processing TaskMgmt id=%d TARGET_RESET\n",
Eric Moore793955f2007-01-29 09:42:20 -0700586 ioc->name, vtarget->id);
Eric Moore547f9a22006-06-27 14:42:12 -0600587 }
588}
589
Christoph Hellwige3094442006-02-16 13:25:36 +0100590static int
Moore, Eric52435432006-03-14 09:14:15 -0700591mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100592 u32 form, u32 form_specific)
593{
594 ConfigExtendedPageHeader_t hdr;
595 CONFIGPARMS cfg;
596 SasEnclosurePage0_t *buffer;
597 dma_addr_t dma_handle;
598 int error;
599 __le64 le_identifier;
600
601 memset(&hdr, 0, sizeof(hdr));
602 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
603 hdr.PageNumber = 0;
604 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
605 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
606
607 cfg.cfghdr.ehdr = &hdr;
608 cfg.physAddr = -1;
609 cfg.pageAddr = form + form_specific;
610 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
611 cfg.dir = 0; /* read */
612 cfg.timeout = 10;
613
614 error = mpt_config(ioc, &cfg);
615 if (error)
616 goto out;
617 if (!hdr.ExtPageLength) {
618 error = -ENXIO;
619 goto out;
620 }
621
622 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
623 &dma_handle);
624 if (!buffer) {
625 error = -ENOMEM;
626 goto out;
627 }
628
629 cfg.physAddr = dma_handle;
630 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
631
632 error = mpt_config(ioc, &cfg);
633 if (error)
634 goto out_free_consistent;
635
636 /* save config data */
637 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
638 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
639 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
640 enclosure->flags = le16_to_cpu(buffer->Flags);
641 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
642 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
643 enclosure->start_id = buffer->StartTargetID;
644 enclosure->start_channel = buffer->StartBus;
645 enclosure->sep_id = buffer->SEPTargetID;
646 enclosure->sep_channel = buffer->SEPBus;
647
648 out_free_consistent:
649 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
650 buffer, dma_handle);
651 out:
652 return error;
653}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200654
James Bottomleyf013db32006-03-18 14:54:36 -0600655static int
656mptsas_slave_configure(struct scsi_device *sdev)
657{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600658
James Bottomleye8bf3942006-07-11 17:49:34 -0400659 if (sdev->channel == MPTSAS_RAID_CHANNEL)
660 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600661
James Bottomleye8bf3942006-07-11 17:49:34 -0400662 sas_read_port_mode_page(sdev);
663
664 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600665 return mptscsih_slave_configure(sdev);
666}
667
Eric Moore547f9a22006-06-27 14:42:12 -0600668static int
669mptsas_target_alloc(struct scsi_target *starget)
670{
671 struct Scsi_Host *host = dev_to_shost(&starget->dev);
672 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
673 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700674 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600675 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;
Eric Moore793955f2007-01-29 09:42:20 -0700685 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
686 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600687 channel = 0;
688
Eric Moore793955f2007-01-29 09:42:20 -0700689 /*
690 * RAID volumes placed beyond the last expected port.
691 */
692 if (starget->channel == MPTSAS_RAID_CHANNEL) {
693 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
694 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
695 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600696 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700697 }
Eric Moore547f9a22006-06-27 14:42:12 -0600698
699 rphy = dev_to_rphy(starget->dev.parent);
700 mutex_lock(&hd->ioc->sas_topology_mutex);
701 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
702 for (i = 0; i < p->num_phys; i++) {
703 if (p->phy_info[i].attached.sas_address !=
704 rphy->identify.sas_address)
705 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700706 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600707 channel = p->phy_info[i].attached.channel;
708 mptsas_set_starget(&p->phy_info[i], starget);
709
710 /*
711 * Exposing hidden raid components
712 */
Eric Moore793955f2007-01-29 09:42:20 -0700713 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
714 id = mptscsih_raid_id_to_num(hd->ioc,
715 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600716 vtarget->tflags |=
717 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700718 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600719 }
720 mutex_unlock(&hd->ioc->sas_topology_mutex);
721 goto out;
722 }
723 }
724 mutex_unlock(&hd->ioc->sas_topology_mutex);
725
726 kfree(vtarget);
727 return -ENXIO;
728
729 out:
Eric Moore793955f2007-01-29 09:42:20 -0700730 vtarget->id = id;
731 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600732 starget->hostdata = vtarget;
733 return 0;
734}
735
736static void
737mptsas_target_destroy(struct scsi_target *starget)
738{
739 struct Scsi_Host *host = dev_to_shost(&starget->dev);
740 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
741 struct sas_rphy *rphy;
742 struct mptsas_portinfo *p;
743 int i;
744
745 if (!starget->hostdata)
746 return;
747
James Bottomleye8bf3942006-07-11 17:49:34 -0400748 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600749 goto out;
750
751 rphy = dev_to_rphy(starget->dev.parent);
752 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
753 for (i = 0; i < p->num_phys; i++) {
754 if (p->phy_info[i].attached.sas_address !=
755 rphy->identify.sas_address)
756 continue;
757 mptsas_set_starget(&p->phy_info[i], NULL);
758 goto out;
759 }
760 }
761
762 out:
763 kfree(starget->hostdata);
764 starget->hostdata = NULL;
765}
766
767
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200768static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700769mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200770{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700771 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200772 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
773 struct sas_rphy *rphy;
774 struct mptsas_portinfo *p;
775 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700776 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600777 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200778
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100779 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200780 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -0600781 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200782 hd->ioc->name, sizeof(VirtDevice));
783 return -ENOMEM;
784 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700785 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -0600786 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200787
James Bottomleye8bf3942006-07-11 17:49:34 -0400788 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -0700789 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700790
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700791 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100792 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200793 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
794 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600795 if (p->phy_info[i].attached.sas_address !=
796 rphy->identify.sas_address)
797 continue;
798 vdev->lun = sdev->lun;
799 /*
800 * Exposing hidden raid components
801 */
802 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700803 p->phy_info[i].attached.channel,
804 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -0600805 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 Moore793955f2007-01-29 09:42:20 -0700826 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -0600827 SCpnt->result = DID_NO_CONNECT << 16;
828 done(SCpnt);
829 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700830 }
Eric Moore547f9a22006-06-27 14:42:12 -0600831
Eric Moore793955f2007-01-29 09:42:20 -0700832// scsi_print_command(SCpnt);
833
Eric Moore547f9a22006-06-27 14:42:12 -0600834 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100835}
836
Eric Moore547f9a22006-06-27 14:42:12 -0600837
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200838static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700839 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200840 .proc_name = "mptsas",
841 .proc_info = mptscsih_proc_info,
842 .name = "MPT SPI Host",
843 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -0600844 .queuecommand = mptsas_qcmd,
845 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200846 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -0600847 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -0600848 .target_destroy = mptsas_target_destroy,
849 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200850 .change_queue_depth = mptscsih_change_queue_depth,
851 .eh_abort_handler = mptscsih_abort,
852 .eh_device_reset_handler = mptscsih_dev_reset,
853 .eh_bus_reset_handler = mptscsih_bus_reset,
854 .eh_host_reset_handler = mptscsih_host_reset,
855 .bios_param = mptscsih_bios_param,
856 .can_queue = MPT_FC_CAN_QUEUE,
857 .this_id = -1,
858 .sg_tablesize = MPT_SCSI_SG_DEPTH,
859 .max_sectors = 8192,
860 .cmd_per_lun = 7,
861 .use_clustering = ENABLE_CLUSTERING,
862};
863
Christoph Hellwigb5141122005-10-28 22:07:41 +0200864static int mptsas_get_linkerrors(struct sas_phy *phy)
865{
866 MPT_ADAPTER *ioc = phy_to_ioc(phy);
867 ConfigExtendedPageHeader_t hdr;
868 CONFIGPARMS cfg;
869 SasPhyPage1_t *buffer;
870 dma_addr_t dma_handle;
871 int error;
872
James Bottomleyf4ad7b52006-08-25 13:48:18 -0500873 /* FIXME: only have link errors on local phys */
874 if (!scsi_is_sas_phy_local(phy))
875 return -EINVAL;
876
Christoph Hellwigb5141122005-10-28 22:07:41 +0200877 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
878 hdr.ExtPageLength = 0;
879 hdr.PageNumber = 1 /* page number 1*/;
880 hdr.Reserved1 = 0;
881 hdr.Reserved2 = 0;
882 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
883 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
884
885 cfg.cfghdr.ehdr = &hdr;
886 cfg.physAddr = -1;
887 cfg.pageAddr = phy->identify.phy_identifier;
888 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
889 cfg.dir = 0; /* read */
890 cfg.timeout = 10;
891
892 error = mpt_config(ioc, &cfg);
893 if (error)
894 return error;
895 if (!hdr.ExtPageLength)
896 return -ENXIO;
897
898 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
899 &dma_handle);
900 if (!buffer)
901 return -ENOMEM;
902
903 cfg.physAddr = dma_handle;
904 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
905
906 error = mpt_config(ioc, &cfg);
907 if (error)
908 goto out_free_consistent;
909
910 mptsas_print_phy_pg1(buffer);
911
912 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
913 phy->running_disparity_error_count =
914 le32_to_cpu(buffer->RunningDisparityErrorCount);
915 phy->loss_of_dword_sync_count =
916 le32_to_cpu(buffer->LossDwordSynchCount);
917 phy->phy_reset_problem_count =
918 le32_to_cpu(buffer->PhyResetProblemCount);
919
920 out_free_consistent:
921 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
922 buffer, dma_handle);
923 return error;
924}
925
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200926static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
927 MPT_FRAME_HDR *reply)
928{
929 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
930 if (reply != NULL) {
931 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
932 memcpy(ioc->sas_mgmt.reply, reply,
933 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
934 }
935 complete(&ioc->sas_mgmt.done);
936 return 1;
937}
938
939static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
940{
941 MPT_ADAPTER *ioc = phy_to_ioc(phy);
942 SasIoUnitControlRequest_t *req;
943 SasIoUnitControlReply_t *reply;
944 MPT_FRAME_HDR *mf;
945 MPIHeader_t *hdr;
946 unsigned long timeleft;
947 int error = -ERESTARTSYS;
948
James Bottomleyf4ad7b52006-08-25 13:48:18 -0500949 /* FIXME: fusion doesn't allow non-local phy reset */
950 if (!scsi_is_sas_phy_local(phy))
951 return -EINVAL;
952
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200953 /* not implemented for expanders */
954 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
955 return -ENXIO;
956
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100957 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200958 goto out;
959
960 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
961 if (!mf) {
962 error = -ENOMEM;
963 goto out_unlock;
964 }
965
966 hdr = (MPIHeader_t *) mf;
967 req = (SasIoUnitControlRequest_t *)mf;
968 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
969 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
970 req->MsgContext = hdr->MsgContext;
971 req->Operation = hard_reset ?
972 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
973 req->PhyNum = phy->identify.phy_identifier;
974
975 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
976
977 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
978 10 * HZ);
979 if (!timeleft) {
980 /* On timeout reset the board */
981 mpt_free_msg_frame(ioc, mf);
982 mpt_HardResetHandler(ioc, CAN_SLEEP);
983 error = -ETIMEDOUT;
984 goto out_unlock;
985 }
986
987 /* a reply frame is expected */
988 if ((ioc->sas_mgmt.status &
989 MPT_IOCTL_STATUS_RF_VALID) == 0) {
990 error = -ENXIO;
991 goto out_unlock;
992 }
993
994 /* process the completed Reply Message Frame */
995 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
996 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
997 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
998 __FUNCTION__,
999 reply->IOCStatus,
1000 reply->IOCLogInfo);
1001 error = -ENXIO;
1002 goto out_unlock;
1003 }
1004
1005 error = 0;
1006
1007 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001008 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001009 out:
1010 return error;
1011}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001012
Christoph Hellwige3094442006-02-16 13:25:36 +01001013static int
1014mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1015{
1016 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1017 int i, error;
1018 struct mptsas_portinfo *p;
1019 struct mptsas_enclosure enclosure_info;
1020 u64 enclosure_handle;
1021
1022 mutex_lock(&ioc->sas_topology_mutex);
1023 list_for_each_entry(p, &ioc->sas_topology, list) {
1024 for (i = 0; i < p->num_phys; i++) {
1025 if (p->phy_info[i].attached.sas_address ==
1026 rphy->identify.sas_address) {
1027 enclosure_handle = p->phy_info[i].
1028 attached.handle_enclosure;
1029 goto found_info;
1030 }
1031 }
1032 }
1033 mutex_unlock(&ioc->sas_topology_mutex);
1034 return -ENXIO;
1035
1036 found_info:
1037 mutex_unlock(&ioc->sas_topology_mutex);
1038 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001039 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001040 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1041 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1042 if (!error)
1043 *identifier = enclosure_info.enclosure_logical_id;
1044 return error;
1045}
1046
1047static int
1048mptsas_get_bay_identifier(struct sas_rphy *rphy)
1049{
1050 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1051 struct mptsas_portinfo *p;
1052 int i, rc;
1053
1054 mutex_lock(&ioc->sas_topology_mutex);
1055 list_for_each_entry(p, &ioc->sas_topology, list) {
1056 for (i = 0; i < p->num_phys; i++) {
1057 if (p->phy_info[i].attached.sas_address ==
1058 rphy->identify.sas_address) {
1059 rc = p->phy_info[i].attached.slot;
1060 goto out;
1061 }
1062 }
1063 }
1064 rc = -ENXIO;
1065 out:
1066 mutex_unlock(&ioc->sas_topology_mutex);
1067 return rc;
1068}
1069
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001070static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001071 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001072 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1073 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001074 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001075};
1076
1077static struct scsi_transport_template *mptsas_transport_template;
1078
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001079static int
1080mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1081{
1082 ConfigExtendedPageHeader_t hdr;
1083 CONFIGPARMS cfg;
1084 SasIOUnitPage0_t *buffer;
1085 dma_addr_t dma_handle;
1086 int error, i;
1087
1088 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1089 hdr.ExtPageLength = 0;
1090 hdr.PageNumber = 0;
1091 hdr.Reserved1 = 0;
1092 hdr.Reserved2 = 0;
1093 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1094 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1095
1096 cfg.cfghdr.ehdr = &hdr;
1097 cfg.physAddr = -1;
1098 cfg.pageAddr = 0;
1099 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1100 cfg.dir = 0; /* read */
1101 cfg.timeout = 10;
1102
1103 error = mpt_config(ioc, &cfg);
1104 if (error)
1105 goto out;
1106 if (!hdr.ExtPageLength) {
1107 error = -ENXIO;
1108 goto out;
1109 }
1110
1111 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1112 &dma_handle);
1113 if (!buffer) {
1114 error = -ENOMEM;
1115 goto out;
1116 }
1117
1118 cfg.physAddr = dma_handle;
1119 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1120
1121 error = mpt_config(ioc, &cfg);
1122 if (error)
1123 goto out_free_consistent;
1124
1125 port_info->num_phys = buffer->NumPhys;
1126 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001127 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001128 if (!port_info->phy_info) {
1129 error = -ENOMEM;
1130 goto out_free_consistent;
1131 }
1132
Moore, Ericdb9c9172006-03-14 09:14:18 -07001133 if (port_info->num_phys)
1134 port_info->handle =
1135 le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001136 for (i = 0; i < port_info->num_phys; i++) {
1137 mptsas_print_phy_data(&buffer->PhyData[i]);
1138 port_info->phy_info[i].phy_id = i;
1139 port_info->phy_info[i].port_id =
1140 buffer->PhyData[i].Port;
1141 port_info->phy_info[i].negotiated_link_rate =
1142 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001143 port_info->phy_info[i].portinfo = port_info;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001144 }
1145
1146 out_free_consistent:
1147 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1148 buffer, dma_handle);
1149 out:
1150 return error;
1151}
1152
1153static int
1154mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1155 u32 form, u32 form_specific)
1156{
1157 ConfigExtendedPageHeader_t hdr;
1158 CONFIGPARMS cfg;
1159 SasPhyPage0_t *buffer;
1160 dma_addr_t dma_handle;
1161 int error;
1162
1163 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1164 hdr.ExtPageLength = 0;
1165 hdr.PageNumber = 0;
1166 hdr.Reserved1 = 0;
1167 hdr.Reserved2 = 0;
1168 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1169 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1170
1171 cfg.cfghdr.ehdr = &hdr;
1172 cfg.dir = 0; /* read */
1173 cfg.timeout = 10;
1174
1175 /* Get Phy Pg 0 for each Phy. */
1176 cfg.physAddr = -1;
1177 cfg.pageAddr = form + form_specific;
1178 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1179
1180 error = mpt_config(ioc, &cfg);
1181 if (error)
1182 goto out;
1183
1184 if (!hdr.ExtPageLength) {
1185 error = -ENXIO;
1186 goto out;
1187 }
1188
1189 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1190 &dma_handle);
1191 if (!buffer) {
1192 error = -ENOMEM;
1193 goto out;
1194 }
1195
1196 cfg.physAddr = dma_handle;
1197 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1198
1199 error = mpt_config(ioc, &cfg);
1200 if (error)
1201 goto out_free_consistent;
1202
1203 mptsas_print_phy_pg0(buffer);
1204
1205 phy_info->hw_link_rate = buffer->HwLinkRate;
1206 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1207 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1208 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1209
1210 out_free_consistent:
1211 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1212 buffer, dma_handle);
1213 out:
1214 return error;
1215}
1216
1217static int
1218mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1219 u32 form, u32 form_specific)
1220{
1221 ConfigExtendedPageHeader_t hdr;
1222 CONFIGPARMS cfg;
1223 SasDevicePage0_t *buffer;
1224 dma_addr_t dma_handle;
1225 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001226 int error=0;
1227
1228 if (ioc->sas_discovery_runtime &&
1229 mptsas_is_end_device(device_info))
1230 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001231
1232 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1233 hdr.ExtPageLength = 0;
1234 hdr.PageNumber = 0;
1235 hdr.Reserved1 = 0;
1236 hdr.Reserved2 = 0;
1237 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1238 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1239
1240 cfg.cfghdr.ehdr = &hdr;
1241 cfg.pageAddr = form + form_specific;
1242 cfg.physAddr = -1;
1243 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1244 cfg.dir = 0; /* read */
1245 cfg.timeout = 10;
1246
Moore, Ericdb9c9172006-03-14 09:14:18 -07001247 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001248 error = mpt_config(ioc, &cfg);
1249 if (error)
1250 goto out;
1251 if (!hdr.ExtPageLength) {
1252 error = -ENXIO;
1253 goto out;
1254 }
1255
1256 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1257 &dma_handle);
1258 if (!buffer) {
1259 error = -ENOMEM;
1260 goto out;
1261 }
1262
1263 cfg.physAddr = dma_handle;
1264 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1265
1266 error = mpt_config(ioc, &cfg);
1267 if (error)
1268 goto out_free_consistent;
1269
1270 mptsas_print_device_pg0(buffer);
1271
1272 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001273 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001274 device_info->handle_enclosure =
1275 le16_to_cpu(buffer->EnclosureHandle);
1276 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001277 device_info->phy_id = buffer->PhyNum;
1278 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001279 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001280 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001281 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001282 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1283 device_info->sas_address = le64_to_cpu(sas_address);
1284 device_info->device_info =
1285 le32_to_cpu(buffer->DeviceInfo);
1286
1287 out_free_consistent:
1288 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1289 buffer, dma_handle);
1290 out:
1291 return error;
1292}
1293
1294static int
1295mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1296 u32 form, u32 form_specific)
1297{
1298 ConfigExtendedPageHeader_t hdr;
1299 CONFIGPARMS cfg;
1300 SasExpanderPage0_t *buffer;
1301 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001302 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001303
1304 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1305 hdr.ExtPageLength = 0;
1306 hdr.PageNumber = 0;
1307 hdr.Reserved1 = 0;
1308 hdr.Reserved2 = 0;
1309 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1310 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1311
1312 cfg.cfghdr.ehdr = &hdr;
1313 cfg.physAddr = -1;
1314 cfg.pageAddr = form + form_specific;
1315 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1316 cfg.dir = 0; /* read */
1317 cfg.timeout = 10;
1318
Moore, Ericdb9c9172006-03-14 09:14:18 -07001319 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001320 error = mpt_config(ioc, &cfg);
1321 if (error)
1322 goto out;
1323
1324 if (!hdr.ExtPageLength) {
1325 error = -ENXIO;
1326 goto out;
1327 }
1328
1329 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1330 &dma_handle);
1331 if (!buffer) {
1332 error = -ENOMEM;
1333 goto out;
1334 }
1335
1336 cfg.physAddr = dma_handle;
1337 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1338
1339 error = mpt_config(ioc, &cfg);
1340 if (error)
1341 goto out_free_consistent;
1342
1343 /* save config data */
1344 port_info->num_phys = buffer->NumPhys;
1345 port_info->handle = le16_to_cpu(buffer->DevHandle);
1346 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001347 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001348 if (!port_info->phy_info) {
1349 error = -ENOMEM;
1350 goto out_free_consistent;
1351 }
1352
Eric Moore547f9a22006-06-27 14:42:12 -06001353 for (i = 0; i < port_info->num_phys; i++)
1354 port_info->phy_info[i].portinfo = port_info;
1355
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001356 out_free_consistent:
1357 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1358 buffer, dma_handle);
1359 out:
1360 return error;
1361}
1362
1363static int
1364mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1365 u32 form, u32 form_specific)
1366{
1367 ConfigExtendedPageHeader_t hdr;
1368 CONFIGPARMS cfg;
1369 SasExpanderPage1_t *buffer;
1370 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001371 int error=0;
1372
1373 if (ioc->sas_discovery_runtime &&
1374 mptsas_is_end_device(&phy_info->attached))
1375 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001376
1377 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1378 hdr.ExtPageLength = 0;
1379 hdr.PageNumber = 1;
1380 hdr.Reserved1 = 0;
1381 hdr.Reserved2 = 0;
1382 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1383 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1384
1385 cfg.cfghdr.ehdr = &hdr;
1386 cfg.physAddr = -1;
1387 cfg.pageAddr = form + form_specific;
1388 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1389 cfg.dir = 0; /* read */
1390 cfg.timeout = 10;
1391
1392 error = mpt_config(ioc, &cfg);
1393 if (error)
1394 goto out;
1395
1396 if (!hdr.ExtPageLength) {
1397 error = -ENXIO;
1398 goto out;
1399 }
1400
1401 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1402 &dma_handle);
1403 if (!buffer) {
1404 error = -ENOMEM;
1405 goto out;
1406 }
1407
1408 cfg.physAddr = dma_handle;
1409 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1410
1411 error = mpt_config(ioc, &cfg);
1412 if (error)
1413 goto out_free_consistent;
1414
1415
1416 mptsas_print_expander_pg1(buffer);
1417
1418 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001419 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001420 phy_info->port_id = buffer->PhysicalPort;
1421 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1422 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1423 phy_info->hw_link_rate = buffer->HwLinkRate;
1424 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1425 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1426
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001427 out_free_consistent:
1428 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1429 buffer, dma_handle);
1430 out:
1431 return error;
1432}
1433
1434static void
1435mptsas_parse_device_info(struct sas_identify *identify,
1436 struct mptsas_devinfo *device_info)
1437{
1438 u16 protocols;
1439
1440 identify->sas_address = device_info->sas_address;
1441 identify->phy_identifier = device_info->phy_id;
1442
1443 /*
1444 * Fill in Phy Initiator Port Protocol.
1445 * Bits 6:3, more than one bit can be set, fall through cases.
1446 */
1447 protocols = device_info->device_info & 0x78;
1448 identify->initiator_port_protocols = 0;
1449 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1450 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1451 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1452 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1453 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1454 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1455 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1456 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1457
1458 /*
1459 * Fill in Phy Target Port Protocol.
1460 * Bits 10:7, more than one bit can be set, fall through cases.
1461 */
1462 protocols = device_info->device_info & 0x780;
1463 identify->target_port_protocols = 0;
1464 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1465 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1466 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1467 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1468 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1469 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1470 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1471 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1472
1473 /*
1474 * Fill in Attached device type.
1475 */
1476 switch (device_info->device_info &
1477 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1478 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1479 identify->device_type = SAS_PHY_UNUSED;
1480 break;
1481 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1482 identify->device_type = SAS_END_DEVICE;
1483 break;
1484 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1485 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1486 break;
1487 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1488 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1489 break;
1490 }
1491}
1492
1493static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001494 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001495{
Moore, Erice6b2d762006-03-14 09:14:24 -07001496 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001497 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001498 struct sas_port *port;
1499 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001500
Eric Moore547f9a22006-06-27 14:42:12 -06001501 if (!dev) {
1502 error = -ENODEV;
1503 goto out;
1504 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001505
1506 if (!phy_info->phy) {
1507 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001508 if (!phy) {
1509 error = -ENOMEM;
1510 goto out;
1511 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001512 } else
1513 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001514
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001515 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001516
1517 /*
1518 * Set Negotiated link rate.
1519 */
1520 switch (phy_info->negotiated_link_rate) {
1521 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001522 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001523 break;
1524 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001525 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001526 break;
1527 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001528 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001529 break;
1530 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001531 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001532 break;
1533 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1534 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1535 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001536 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001537 break;
1538 }
1539
1540 /*
1541 * Set Max hardware link rate.
1542 */
1543 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1544 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001545 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001546 break;
1547 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001548 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001549 break;
1550 default:
1551 break;
1552 }
1553
1554 /*
1555 * Set Max programmed link rate.
1556 */
1557 switch (phy_info->programmed_link_rate &
1558 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1559 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001560 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001561 break;
1562 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001563 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001564 break;
1565 default:
1566 break;
1567 }
1568
1569 /*
1570 * Set Min hardware link rate.
1571 */
1572 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1573 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001574 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001575 break;
1576 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001577 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001578 break;
1579 default:
1580 break;
1581 }
1582
1583 /*
1584 * Set Min programmed link rate.
1585 */
1586 switch (phy_info->programmed_link_rate &
1587 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1588 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001589 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001590 break;
1591 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001592 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001593 break;
1594 default:
1595 break;
1596 }
1597
Moore, Erice6b2d762006-03-14 09:14:24 -07001598 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001599
Moore, Erice6b2d762006-03-14 09:14:24 -07001600 error = sas_phy_add(phy);
1601 if (error) {
1602 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001603 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001604 }
1605 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001606 }
1607
Eric Moore547f9a22006-06-27 14:42:12 -06001608 if (!phy_info->attached.handle ||
1609 !phy_info->port_details)
1610 goto out;
1611
1612 port = mptsas_get_port(phy_info);
1613 ioc = phy_to_ioc(phy_info->phy);
1614
1615 if (phy_info->sas_port_add_phy) {
1616
1617 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001618 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001619 if (!port) {
1620 error = -ENOMEM;
1621 goto out;
1622 }
1623 error = sas_port_add(port);
1624 if (error) {
1625 dfailprintk((MYIOC_s_ERR_FMT
1626 "%s: exit at line=%d\n", ioc->name,
1627 __FUNCTION__, __LINE__));
1628 goto out;
1629 }
1630 mptsas_set_port(phy_info, port);
Eric Mooredc22f162006-07-06 11:23:14 -06001631 dsaswideprintk((KERN_DEBUG
1632 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1633 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001634 }
1635 dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
1636 phy_info->phy_id));
1637 sas_port_add_phy(port, phy_info->phy);
1638 phy_info->sas_port_add_phy = 0;
1639 }
1640
1641 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001642
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001643 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001644 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001645 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001646
James Bottomley2686de22006-06-30 12:54:02 -05001647 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001648 /*
1649 * Let the hotplug_work thread handle processing
1650 * the adding/removing of devices that occur
1651 * after start of day.
1652 */
1653 if (ioc->sas_discovery_runtime &&
1654 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001655 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001656
James Bottomleyf013db32006-03-18 14:54:36 -06001657 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001658 if (scsi_is_host_device(parent)) {
1659 struct mptsas_portinfo *port_info;
1660 int i;
1661
1662 mutex_lock(&ioc->sas_topology_mutex);
1663 port_info = mptsas_find_portinfo_by_handle(ioc,
1664 ioc->handle);
1665 mutex_unlock(&ioc->sas_topology_mutex);
1666
1667 for (i = 0; i < port_info->num_phys; i++)
1668 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001669 identify.sas_address) {
1670 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001671 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001672 }
James Bottomley2686de22006-06-30 12:54:02 -05001673
1674 } else if (scsi_is_sas_rphy(parent)) {
1675 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
1676 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001677 parent_rphy->identify.sas_address) {
1678 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001679 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001680 }
James Bottomley2686de22006-06-30 12:54:02 -05001681 }
1682
James Bottomleyf013db32006-03-18 14:54:36 -06001683 switch (identify.device_type) {
1684 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001685 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06001686 break;
1687 case SAS_EDGE_EXPANDER_DEVICE:
1688 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001689 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06001690 break;
1691 default:
1692 rphy = NULL;
1693 break;
1694 }
Eric Moore547f9a22006-06-27 14:42:12 -06001695 if (!rphy) {
1696 dfailprintk((MYIOC_s_ERR_FMT
1697 "%s: exit at line=%d\n", ioc->name,
1698 __FUNCTION__, __LINE__));
1699 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001700 }
1701
Eric Moore547f9a22006-06-27 14:42:12 -06001702 rphy->identify = identify;
1703 error = sas_rphy_add(rphy);
1704 if (error) {
1705 dfailprintk((MYIOC_s_ERR_FMT
1706 "%s: exit at line=%d\n", ioc->name,
1707 __FUNCTION__, __LINE__));
1708 sas_rphy_free(rphy);
1709 goto out;
1710 }
1711 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001712 }
1713
Eric Moore547f9a22006-06-27 14:42:12 -06001714 out:
1715 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001716}
1717
1718static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001719mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001720{
Moore, Erice6b2d762006-03-14 09:14:24 -07001721 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001722 u32 handle = 0xFFFF;
1723 int error = -ENOMEM, i;
1724
Moore, Erice6b2d762006-03-14 09:14:24 -07001725 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1726 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001727 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001728
Moore, Erice6b2d762006-03-14 09:14:24 -07001729 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001730 if (error)
1731 goto out_free_port_info;
1732
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001733 mutex_lock(&ioc->sas_topology_mutex);
James Bottomley2686de22006-06-30 12:54:02 -05001734 ioc->handle = hba->handle;
Moore, Erice6b2d762006-03-14 09:14:24 -07001735 port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
1736 if (!port_info) {
1737 port_info = hba;
1738 list_add_tail(&port_info->list, &ioc->sas_topology);
1739 } else {
1740 port_info->handle = hba->handle;
1741 for (i = 0; i < hba->num_phys; i++)
1742 port_info->phy_info[i].negotiated_link_rate =
1743 hba->phy_info[i].negotiated_link_rate;
Eric Moore547f9a22006-06-27 14:42:12 -06001744 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001745 kfree(hba);
1746 hba = NULL;
1747 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001748 mutex_unlock(&ioc->sas_topology_mutex);
1749
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001750 for (i = 0; i < port_info->num_phys; i++) {
1751 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1752 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1753 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1754
1755 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1756 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1757 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001758 port_info->phy_info[i].identify.phy_id =
1759 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001760 handle = port_info->phy_info[i].identify.handle;
1761
Eric Moore547f9a22006-06-27 14:42:12 -06001762 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001763 mptsas_sas_device_pg0(ioc,
1764 &port_info->phy_info[i].attached,
1765 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1766 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1767 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06001768 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001769
Eric Moore547f9a22006-06-27 14:42:12 -06001770 mptsas_setup_wide_ports(ioc, port_info);
1771
1772 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001773 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07001774 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001775
1776 return 0;
1777
1778 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06001779 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001780 out:
1781 return error;
1782}
1783
1784static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001785mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001786{
Moore, Erice6b2d762006-03-14 09:14:24 -07001787 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06001788 struct device *parent;
1789 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001790 int error = -ENOMEM, i, j;
1791
Moore, Erice6b2d762006-03-14 09:14:24 -07001792 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1793 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001794 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001795
Moore, Erice6b2d762006-03-14 09:14:24 -07001796 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001797 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1798 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1799 if (error)
1800 goto out_free_port_info;
1801
Moore, Erice6b2d762006-03-14 09:14:24 -07001802 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001803
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001804 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001805 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1806 if (!port_info) {
1807 port_info = ex;
1808 list_add_tail(&port_info->list, &ioc->sas_topology);
1809 } else {
1810 port_info->handle = ex->handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001811 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001812 kfree(ex);
1813 ex = NULL;
1814 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001815 mutex_unlock(&ioc->sas_topology_mutex);
1816
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001817 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001818 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1819 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1820 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1821
1822 if (port_info->phy_info[i].identify.handle) {
1823 mptsas_sas_device_pg0(ioc,
1824 &port_info->phy_info[i].identify,
1825 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1826 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1827 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001828 port_info->phy_info[i].identify.phy_id =
1829 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001830 }
1831
1832 if (port_info->phy_info[i].attached.handle) {
1833 mptsas_sas_device_pg0(ioc,
1834 &port_info->phy_info[i].attached,
1835 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1836 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1837 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001838 port_info->phy_info[i].attached.phy_id =
1839 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840 }
Eric Moore547f9a22006-06-27 14:42:12 -06001841 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001842
Eric Moore547f9a22006-06-27 14:42:12 -06001843 parent = &ioc->sh->shost_gendev;
1844 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001845 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001846 list_for_each_entry(p, &ioc->sas_topology, list) {
1847 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001848 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001849 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06001850 continue;
1851 rphy = mptsas_get_rphy(&p->phy_info[j]);
1852 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853 }
1854 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001855 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001856 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857
Eric Moore547f9a22006-06-27 14:42:12 -06001858 mptsas_setup_wide_ports(ioc, port_info);
1859
1860 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001861 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001862 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001863
1864 return 0;
1865
1866 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001867 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06001868 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001869 kfree(ex);
1870 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001871 out:
1872 return error;
1873}
1874
Moore, Erice6b2d762006-03-14 09:14:24 -07001875/*
1876 * mptsas_delete_expander_phys
1877 *
1878 *
1879 * This will traverse topology, and remove expanders
1880 * that are no longer present
1881 */
1882static void
1883mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1884{
1885 struct mptsas_portinfo buffer;
1886 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06001887 struct mptsas_phyinfo *phy_info;
1888 struct scsi_target * starget;
1889 VirtTarget * vtarget;
1890 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07001891 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06001892 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07001893
1894 mutex_lock(&ioc->sas_topology_mutex);
1895 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1896
1897 if (port_info->phy_info &&
1898 (!(port_info->phy_info[0].identify.device_info &
1899 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1900 continue;
1901
1902 if (mptsas_sas_expander_pg0(ioc, &buffer,
1903 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1904 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1905
1906 /*
Eric Moore547f9a22006-06-27 14:42:12 -06001907 * Issue target reset to all child end devices
1908 * then mark them deleted to prevent further
1909 * IO going to them.
1910 */
1911 phy_info = port_info->phy_info;
1912 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
1913 starget = mptsas_get_starget(phy_info);
1914 if (!starget)
1915 continue;
1916 vtarget = starget->hostdata;
1917 if(vtarget->deleted)
1918 continue;
1919 vtarget->deleted = 1;
1920 mptsas_target_reset(ioc, vtarget);
1921 sas_port_delete(mptsas_get_port(phy_info));
1922 mptsas_port_delete(phy_info->port_details);
1923 }
1924
1925 /*
Moore, Erice6b2d762006-03-14 09:14:24 -07001926 * Obtain the port_info instance to the parent port
1927 */
1928 parent = mptsas_find_portinfo_by_handle(ioc,
1929 port_info->phy_info[0].identify.handle_parent);
1930
1931 if (!parent)
1932 goto next_port;
1933
Eric Moore547f9a22006-06-27 14:42:12 -06001934 expander_sas_address =
1935 port_info->phy_info[0].identify.sas_address;
1936
Moore, Erice6b2d762006-03-14 09:14:24 -07001937 /*
1938 * Delete rphys in the parent that point
1939 * to this expander. The transport layer will
1940 * cleanup all the children.
1941 */
Eric Moore547f9a22006-06-27 14:42:12 -06001942 phy_info = parent->phy_info;
1943 for (i = 0; i < parent->num_phys; i++, phy_info++) {
1944 port = mptsas_get_port(phy_info);
1945 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07001946 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06001947 if (phy_info->attached.sas_address !=
1948 expander_sas_address)
1949 continue;
1950#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06001951 dev_printk(KERN_DEBUG, &port->dev,
1952 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06001953#endif
1954 sas_port_delete(port);
1955 mptsas_port_delete(phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07001956 }
1957 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06001958
1959 phy_info = port_info->phy_info;
1960 for (i = 0; i < port_info->num_phys; i++, phy_info++)
1961 mptsas_port_delete(phy_info->port_details);
1962
Moore, Erice6b2d762006-03-14 09:14:24 -07001963 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06001964 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001965 kfree(port_info);
1966 }
1967 /*
1968 * Free this memory allocated from inside
1969 * mptsas_sas_expander_pg0
1970 */
Eric Moore547f9a22006-06-27 14:42:12 -06001971 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07001972 }
1973 mutex_unlock(&ioc->sas_topology_mutex);
1974}
1975
1976/*
1977 * Start of day discovery
1978 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001979static void
1980mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1981{
1982 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001983 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001984
Moore, Erice6b2d762006-03-14 09:14:24 -07001985 mutex_lock(&ioc->sas_discovery_mutex);
1986 mptsas_probe_hba_phys(ioc);
1987 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001988 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001989 /*
1990 Reporting RAID volumes.
1991 */
Eric Mooreb506ade2007-01-29 09:45:37 -07001992 if (!ioc->ir_firmware)
1993 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07001994 if (!ioc->raid_data.pIocPg2)
1995 goto out;
1996 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1997 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001998 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04001999 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002000 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2001 }
2002 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002003 mutex_unlock(&ioc->sas_discovery_mutex);
2004}
2005
2006/*
2007 * Work queue thread to handle Runtime discovery
2008 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002009 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002010 */
2011static void
Eric Moore547f9a22006-06-27 14:42:12 -06002012__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002013{
Moore, Erice6b2d762006-03-14 09:14:24 -07002014 u32 handle = 0xFFFF;
2015
Moore, Erice6b2d762006-03-14 09:14:24 -07002016 ioc->sas_discovery_runtime=1;
2017 mptsas_delete_expander_phys(ioc);
2018 mptsas_probe_hba_phys(ioc);
2019 while (!mptsas_probe_expander_phys(ioc, &handle))
2020 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002021 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002022}
2023
2024/*
2025 * Work queue thread to handle Runtime discovery
2026 * Mere purpose is the hot add/delete of expanders
2027 *(Mutex LOCKED)
2028 */
2029static void
David Howellsc4028952006-11-22 14:57:56 +00002030mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002031{
David Howellsc4028952006-11-22 14:57:56 +00002032 struct mptsas_discovery_event *ev =
2033 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002034 MPT_ADAPTER *ioc = ev->ioc;
2035
2036 mutex_lock(&ioc->sas_discovery_mutex);
2037 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002038 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002039 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002040}
2041
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002042static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002043mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002044{
2045 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002046 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002047 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002048
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002049 mutex_lock(&ioc->sas_topology_mutex);
2050 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2051 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002052 if (!mptsas_is_end_device(
2053 &port_info->phy_info[i].attached))
2054 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002055 if (port_info->phy_info[i].attached.sas_address
2056 != sas_address)
2057 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002058 phy_info = &port_info->phy_info[i];
2059 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002060 }
2061 }
2062 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002063 return phy_info;
2064}
2065
2066static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002067mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002068{
2069 struct mptsas_portinfo *port_info;
2070 struct mptsas_phyinfo *phy_info = NULL;
2071 int i;
2072
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002073 mutex_lock(&ioc->sas_topology_mutex);
2074 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002075 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002076 if (!mptsas_is_end_device(
2077 &port_info->phy_info[i].attached))
2078 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002079 if (port_info->phy_info[i].attached.id != id)
2080 continue;
2081 if (port_info->phy_info[i].attached.channel != channel)
2082 continue;
2083 phy_info = &port_info->phy_info[i];
2084 break;
2085 }
2086 }
2087 mutex_unlock(&ioc->sas_topology_mutex);
2088 return phy_info;
2089}
2090
2091static struct mptsas_phyinfo *
2092mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2093{
2094 struct mptsas_portinfo *port_info;
2095 struct mptsas_phyinfo *phy_info = NULL;
2096 int i;
2097
2098 mutex_lock(&ioc->sas_topology_mutex);
2099 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2100 for (i = 0; i < port_info->num_phys; i++) {
2101 if (!mptsas_is_end_device(
2102 &port_info->phy_info[i].attached))
2103 continue;
2104 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2105 continue;
2106 if (port_info->phy_info[i].attached.phys_disk_num != id)
2107 continue;
2108 if (port_info->phy_info[i].attached.channel != channel)
2109 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002110 phy_info = &port_info->phy_info[i];
2111 break;
2112 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002113 }
2114 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002115 return phy_info;
2116}
2117
Moore, Eric4b766472006-03-14 09:14:12 -07002118/*
2119 * Work queue thread to clear the persitency table
2120 */
2121static void
David Howellsc4028952006-11-22 14:57:56 +00002122mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002123{
David Howellsc4028952006-11-22 14:57:56 +00002124 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002125
2126 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2127}
2128
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002129static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002130mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2131{
Eric Mooref99be432007-01-04 20:46:54 -07002132 int rc;
2133
Moore, Ericf44e5462006-03-14 09:14:21 -07002134 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002135 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002136}
2137
2138static void
2139mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2140{
2141 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2142 mptsas_reprobe_lun);
2143}
2144
Eric Mooreb506ade2007-01-29 09:45:37 -07002145static void
2146mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2147{
2148 CONFIGPARMS cfg;
2149 ConfigPageHeader_t hdr;
2150 dma_addr_t dma_handle;
2151 pRaidVolumePage0_t buffer = NULL;
2152 RaidPhysDiskPage0_t phys_disk;
2153 int i;
2154 struct mptsas_hotplug_event *ev;
2155
2156 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2157 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2158 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2159 cfg.pageAddr = (channel << 8) + id;
2160 cfg.cfghdr.hdr = &hdr;
2161 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2162
2163 if (mpt_config(ioc, &cfg) != 0)
2164 goto out;
2165
2166 if (!hdr.PageLength)
2167 goto out;
2168
2169 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2170 &dma_handle);
2171
2172 if (!buffer)
2173 goto out;
2174
2175 cfg.physAddr = dma_handle;
2176 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2177
2178 if (mpt_config(ioc, &cfg) != 0)
2179 goto out;
2180
2181 if (!(buffer->VolumeStatus.Flags &
2182 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2183 goto out;
2184
2185 if (!buffer->NumPhysDisks)
2186 goto out;
2187
2188 for (i = 0; i < buffer->NumPhysDisks; i++) {
2189
2190 if (mpt_raid_phys_disk_pg0(ioc,
2191 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2192 continue;
2193
2194 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2195 if (!ev) {
2196 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2197 goto out;
2198 }
2199
2200 INIT_WORK(&ev->work, mptsas_hotplug_work);
2201 ev->ioc = ioc;
2202 ev->id = phys_disk.PhysDiskID;
2203 ev->channel = phys_disk.PhysDiskBus;
2204 ev->phys_disk_num_valid = 1;
2205 ev->phys_disk_num = phys_disk.PhysDiskNum;
2206 ev->event_type = MPTSAS_ADD_DEVICE;
2207 schedule_work(&ev->work);
2208 }
2209
2210 out:
2211 if (buffer)
2212 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2213 dma_handle);
2214}
Moore, Erice6b2d762006-03-14 09:14:24 -07002215/*
2216 * Work queue thread to handle SAS hotplug events
2217 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002218static void
David Howellsc4028952006-11-22 14:57:56 +00002219mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002220{
David Howellsc4028952006-11-22 14:57:56 +00002221 struct mptsas_hotplug_event *ev =
2222 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002223
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002224 MPT_ADAPTER *ioc = ev->ioc;
2225 struct mptsas_phyinfo *phy_info;
2226 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002227 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002228 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002229 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002230 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002231 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002232 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002233 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002234 VirtDevice *vdevice;
2235
Moore, Erice6b2d762006-03-14 09:14:24 -07002236 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002237 switch (ev->event_type) {
2238 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002239
Eric Mooreb506ade2007-01-29 09:45:37 -07002240 phy_info = NULL;
2241 if (ev->phys_disk_num_valid) {
2242 if (ev->hidden_raid_component){
2243 if (mptsas_sas_device_pg0(ioc, &sas_device,
2244 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2245 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2246 (ev->channel << 8) + ev->id)) {
2247 dfailprintk((MYIOC_s_ERR_FMT
2248 "%s: exit at line=%d\n", ioc->name,
2249 __FUNCTION__, __LINE__));
2250 break;
2251 }
2252 phy_info = mptsas_find_phyinfo_by_sas_address(
2253 ioc, sas_device.sas_address);
2254 }else
2255 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2256 ioc, ev->channel, ev->phys_disk_num);
2257 }
2258
2259 if (!phy_info)
2260 phy_info = mptsas_find_phyinfo_by_target(ioc,
2261 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002262
Moore, Ericf44e5462006-03-14 09:14:21 -07002263 /*
2264 * Sanity checks, for non-existing phys and remote rphys.
2265 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002266 if (!phy_info){
2267 dfailprintk((MYIOC_s_ERR_FMT
2268 "%s: exit at line=%d\n", ioc->name,
2269 __FUNCTION__, __LINE__));
2270 break;
2271 }
2272 if (!phy_info->port_details) {
Eric Moore547f9a22006-06-27 14:42:12 -06002273 dfailprintk((MYIOC_s_ERR_FMT
2274 "%s: exit at line=%d\n", ioc->name,
2275 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002276 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002277 }
2278 rphy = mptsas_get_rphy(phy_info);
2279 if (!rphy) {
2280 dfailprintk((MYIOC_s_ERR_FMT
2281 "%s: exit at line=%d\n", ioc->name,
2282 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002283 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002284 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002285
Eric Moore547f9a22006-06-27 14:42:12 -06002286 port = mptsas_get_port(phy_info);
2287 if (!port) {
2288 dfailprintk((MYIOC_s_ERR_FMT
2289 "%s: exit at line=%d\n", ioc->name,
2290 __FUNCTION__, __LINE__));
2291 break;
2292 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002293
Eric Moore547f9a22006-06-27 14:42:12 -06002294 starget = mptsas_get_starget(phy_info);
2295 if (starget) {
2296 vtarget = starget->hostdata;
2297
2298 if (!vtarget) {
2299 dfailprintk((MYIOC_s_ERR_FMT
2300 "%s: exit at line=%d\n", ioc->name,
2301 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002302 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002303 }
2304
Moore, Ericf44e5462006-03-14 09:14:21 -07002305 /*
2306 * Handling RAID components
2307 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002308 if (ev->phys_disk_num_valid &&
2309 ev->hidden_raid_component) {
2310 printk(MYIOC_s_INFO_FMT
2311 "RAID Hidding: channel=%d, id=%d, "
2312 "physdsk %d \n", ioc->name, ev->channel,
2313 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002314 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002315 vtarget->tflags |=
2316 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002317 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002318 phy_info->attached.phys_disk_num =
2319 ev->phys_disk_num;
2320 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002321 }
Eric Moore547f9a22006-06-27 14:42:12 -06002322
2323 vtarget->deleted = 1;
2324 mptsas_target_reset(ioc, vtarget);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002325 }
2326
Eric Mooreb506ade2007-01-29 09:45:37 -07002327 if (phy_info->attached.device_info &
2328 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002329 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002330 if (phy_info->attached.device_info &
2331 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002332 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002333 if (phy_info->attached.device_info &
2334 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002335 ds = "sata";
2336
2337 printk(MYIOC_s_INFO_FMT
2338 "removing %s device, channel %d, id %d, phy %d\n",
2339 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore547f9a22006-06-27 14:42:12 -06002340#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002341 dev_printk(KERN_DEBUG, &port->dev,
2342 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002343#endif
2344 sas_port_delete(port);
2345 mptsas_port_delete(phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002346 break;
2347 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002348
Moore, Ericbd23e942006-04-17 12:43:04 -06002349 if (ev->phys_disk_num_valid)
2350 mpt_findImVolumes(ioc);
2351
Moore, Ericc73787ee2006-01-26 16:20:06 -07002352 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002353 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002354 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002355 if (mptsas_sas_device_pg0(ioc, &sas_device,
2356 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002357 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2358 (ev->channel << 8) + ev->id)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002359 dfailprintk((MYIOC_s_ERR_FMT
2360 "%s: exit at line=%d\n", ioc->name,
2361 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002362 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002363 }
2364
Eric Moore547f9a22006-06-27 14:42:12 -06002365 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002366
Eric Moore547f9a22006-06-27 14:42:12 -06002367 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2368 sas_device.sas_address);
2369
2370 if (!phy_info || !phy_info->port_details) {
2371 dfailprintk((MYIOC_s_ERR_FMT
2372 "%s: exit at line=%d\n", ioc->name,
2373 __FUNCTION__, __LINE__));
2374 break;
2375 }
2376
2377 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002378 if (starget && (!ev->hidden_raid_component)){
2379
Eric Moore547f9a22006-06-27 14:42:12 -06002380 vtarget = starget->hostdata;
2381
2382 if (!vtarget) {
2383 dfailprintk((MYIOC_s_ERR_FMT
2384 "%s: exit at line=%d\n", ioc->name,
2385 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002386 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002387 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002388 /*
2389 * Handling RAID components
2390 */
2391 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002392 printk(MYIOC_s_INFO_FMT
2393 "RAID Exposing: channel=%d, id=%d, "
2394 "physdsk %d \n", ioc->name, ev->channel,
2395 ev->id, ev->phys_disk_num);
2396 vtarget->tflags &=
2397 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002398 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002399 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002400 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002401 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002402 break;
2403 }
2404
Eric Moore547f9a22006-06-27 14:42:12 -06002405 if (mptsas_get_rphy(phy_info)) {
2406 dfailprintk((MYIOC_s_ERR_FMT
2407 "%s: exit at line=%d\n", ioc->name,
2408 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002409 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002410 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002411 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002412
Eric Moore547f9a22006-06-27 14:42:12 -06002413 port = mptsas_get_port(phy_info);
2414 if (!port) {
2415 dfailprintk((MYIOC_s_ERR_FMT
2416 "%s: exit at line=%d\n", ioc->name,
2417 __FUNCTION__, __LINE__));
2418 break;
2419 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002420 memcpy(&phy_info->attached, &sas_device,
2421 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002422
Eric Mooreb506ade2007-01-29 09:45:37 -07002423 if (phy_info->attached.device_info &
2424 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002425 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002426 if (phy_info->attached.device_info &
2427 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002428 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002429 if (phy_info->attached.device_info &
2430 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002431 ds = "sata";
2432
2433 printk(MYIOC_s_INFO_FMT
2434 "attaching %s device, channel %d, id %d, phy %d\n",
2435 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2436
James Bottomleyf013db32006-03-18 14:54:36 -06002437 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002438 rphy = sas_end_device_alloc(port);
2439 if (!rphy) {
2440 dfailprintk((MYIOC_s_ERR_FMT
2441 "%s: exit at line=%d\n", ioc->name,
2442 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002443 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002444 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002445
James Bottomleyf013db32006-03-18 14:54:36 -06002446 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002447 if (sas_rphy_add(rphy)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002448 dfailprintk((MYIOC_s_ERR_FMT
2449 "%s: exit at line=%d\n", ioc->name,
2450 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002451 sas_rphy_free(rphy);
2452 break;
2453 }
Eric Moore547f9a22006-06-27 14:42:12 -06002454 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002455 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002456 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002457 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2458 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002459 if (sdev) {
2460 scsi_device_put(sdev);
2461 break;
2462 }
2463 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002464 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002465 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2466 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002467 mpt_findImVolumes(ioc);
2468 break;
2469 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002470 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002471 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002472 if (!sdev)
2473 break;
2474 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002475 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002476 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Moore547f9a22006-06-27 14:42:12 -06002477 vdevice->vtarget->deleted = 1;
2478 mptsas_target_reset(ioc, vdevice->vtarget);
Eric Mooreb506ade2007-01-29 09:45:37 -07002479 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002480 scsi_remove_device(sdev);
2481 scsi_device_put(sdev);
2482 mpt_findImVolumes(ioc);
2483 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002484 case MPTSAS_ADD_INACTIVE_VOLUME:
2485 mptsas_adding_inactive_raid_components(ioc,
2486 ev->channel, ev->id);
2487 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002488 case MPTSAS_IGNORE_EVENT:
2489 default:
2490 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002491 }
2492
Moore, Erice6b2d762006-03-14 09:14:24 -07002493 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002494 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002495}
2496
2497static void
Eric Moore547f9a22006-06-27 14:42:12 -06002498mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002499 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2500{
2501 struct mptsas_hotplug_event *ev;
2502 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2503 __le64 sas_address;
2504
2505 if ((device_info &
2506 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2507 MPI_SAS_DEVICE_INFO_STP_TARGET |
2508 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2509 return;
2510
Moore, Eric4b766472006-03-14 09:14:12 -07002511 switch (sas_event_data->ReasonCode) {
2512 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
2513 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore547f9a22006-06-27 14:42:12 -06002514 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002515 if (!ev) {
2516 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2517 break;
2518 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002519
David Howellsc4028952006-11-22 14:57:56 +00002520 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002521 ev->ioc = ioc;
2522 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2523 ev->parent_handle =
2524 le16_to_cpu(sas_event_data->ParentDevHandle);
2525 ev->channel = sas_event_data->Bus;
2526 ev->id = sas_event_data->TargetID;
2527 ev->phy_id = sas_event_data->PhyNum;
2528 memcpy(&sas_address, &sas_event_data->SASAddress,
2529 sizeof(__le64));
2530 ev->sas_address = le64_to_cpu(sas_address);
2531 ev->device_info = device_info;
2532
2533 if (sas_event_data->ReasonCode &
2534 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2535 ev->event_type = MPTSAS_ADD_DEVICE;
2536 else
2537 ev->event_type = MPTSAS_DEL_DEVICE;
2538 schedule_work(&ev->work);
2539 break;
2540 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2541 /*
2542 * Persistent table is full.
2543 */
Eric Moore547f9a22006-06-27 14:42:12 -06002544 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002545 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002546 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002547 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002548 /*
2549 * TODO, handle other events
2550 */
Moore, Eric4b766472006-03-14 09:14:12 -07002551 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002552 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002553 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002554 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2555 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2556 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2557 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002558 default:
2559 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002560 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002561}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002562static void
Eric Moore547f9a22006-06-27 14:42:12 -06002563mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002564 EVENT_DATA_RAID *raid_event_data)
2565{
2566 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002567 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2568 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002569
2570 if (ioc->bus_type != SAS)
2571 return;
2572
Eric Moore547f9a22006-06-27 14:42:12 -06002573 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002574 if (!ev) {
2575 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2576 return;
2577 }
2578
David Howellsc4028952006-11-22 14:57:56 +00002579 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002580 ev->ioc = ioc;
2581 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002582 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002583 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002584
2585 switch (raid_event_data->ReasonCode) {
2586 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002587 ev->phys_disk_num_valid = 1;
2588 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002589 ev->event_type = MPTSAS_ADD_DEVICE;
2590 break;
2591 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002592 ev->phys_disk_num_valid = 1;
2593 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002594 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002595 ev->event_type = MPTSAS_DEL_DEVICE;
2596 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002597 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2598 switch (state) {
2599 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002600 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002601 ev->phys_disk_num_valid = 1;
2602 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002603 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002604 ev->event_type = MPTSAS_ADD_DEVICE;
2605 break;
2606 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002607 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2608 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2609 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002610 ev->phys_disk_num_valid = 1;
2611 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002612 ev->event_type = MPTSAS_DEL_DEVICE;
2613 break;
2614 default:
2615 break;
2616 }
2617 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002618 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2619 ev->event_type = MPTSAS_DEL_RAID;
2620 break;
2621 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2622 ev->event_type = MPTSAS_ADD_RAID;
2623 break;
2624 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002625 switch (state) {
2626 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2627 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2628 ev->event_type = MPTSAS_DEL_RAID;
2629 break;
2630 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2631 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2632 ev->event_type = MPTSAS_ADD_RAID;
2633 break;
2634 default:
2635 break;
2636 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002637 break;
2638 default:
2639 break;
2640 }
2641 schedule_work(&ev->work);
2642}
2643
Moore, Erice6b2d762006-03-14 09:14:24 -07002644static void
Eric Moore547f9a22006-06-27 14:42:12 -06002645mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002646 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2647{
2648 struct mptsas_discovery_event *ev;
2649
2650 /*
2651 * DiscoveryStatus
2652 *
2653 * This flag will be non-zero when firmware
2654 * kicks off discovery, and return to zero
2655 * once its completed.
2656 */
2657 if (discovery_data->DiscoveryStatus)
2658 return;
2659
Eric Moore547f9a22006-06-27 14:42:12 -06002660 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002661 if (!ev)
2662 return;
David Howellsc4028952006-11-22 14:57:56 +00002663 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002664 ev->ioc = ioc;
2665 schedule_work(&ev->work);
2666};
2667
Eric Mooreb506ade2007-01-29 09:45:37 -07002668/*
2669 * mptsas_send_ir2_event - handle exposing hidden disk when
2670 * an inactive raid volume is added
2671 *
2672 * @ioc: Pointer to MPT_ADAPTER structure
2673 * @ir2_data
2674 *
2675 */
2676static void
2677mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2678{
2679 struct mptsas_hotplug_event *ev;
2680
2681 if (ir2_data->ReasonCode !=
2682 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2683 return;
2684
2685 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2686 if (!ev)
2687 return;
2688
2689 INIT_WORK(&ev->work, mptsas_hotplug_work);
2690 ev->ioc = ioc;
2691 ev->id = ir2_data->TargetID;
2692 ev->channel = ir2_data->Bus;
2693 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
2694
2695 schedule_work(&ev->work);
2696};
Moore, Erice6b2d762006-03-14 09:14:24 -07002697
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002698static int
2699mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2700{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002701 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002702 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2703
2704 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002705 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002706
Moore, Erice6b2d762006-03-14 09:14:24 -07002707 /*
2708 * sas_discovery_ignore_events
2709 *
2710 * This flag is to prevent anymore processing of
2711 * sas events once mptsas_remove function is called.
2712 */
2713 if (ioc->sas_discovery_ignore_events) {
2714 rc = mptscsih_event_process(ioc, reply);
2715 goto out;
2716 }
2717
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002718 switch (event) {
2719 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06002720 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002721 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002722 break;
2723 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06002724 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002725 (EVENT_DATA_RAID *)reply->Data);
2726 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002727 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06002728 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002729 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002730 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07002731 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002732 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06002733 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002734 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2735 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002736 case MPI_EVENT_IR2:
2737 mptsas_send_ir2_event(ioc,
2738 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
2739 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002740 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002741 rc = mptscsih_event_process(ioc, reply);
2742 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002743 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002744 out:
2745
2746 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002747}
2748
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002749static int
2750mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2751{
2752 struct Scsi_Host *sh;
2753 MPT_SCSI_HOST *hd;
2754 MPT_ADAPTER *ioc;
2755 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002756 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002757 int numSGE = 0;
2758 int scale;
2759 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002760 int error=0;
2761 int r;
2762
2763 r = mpt_attach(pdev,id);
2764 if (r)
2765 return r;
2766
2767 ioc = pci_get_drvdata(pdev);
2768 ioc->DoneCtx = mptsasDoneCtx;
2769 ioc->TaskCtx = mptsasTaskCtx;
2770 ioc->InternalCtx = mptsasInternalCtx;
2771
2772 /* Added sanity check on readiness of the MPT adapter.
2773 */
2774 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2775 printk(MYIOC_s_WARN_FMT
2776 "Skipping because it's not operational!\n",
2777 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002778 error = -ENODEV;
2779 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002780 }
2781
2782 if (!ioc->active) {
2783 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2784 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002785 error = -ENODEV;
2786 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002787 }
2788
2789 /* Sanity check - ensure at least 1 port is INITIATOR capable
2790 */
2791 ioc_cap = 0;
2792 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2793 if (ioc->pfacts[ii].ProtocolFlags &
2794 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2795 ioc_cap++;
2796 }
2797
2798 if (!ioc_cap) {
2799 printk(MYIOC_s_WARN_FMT
2800 "Skipping ioc=%p because SCSI Initiator mode "
2801 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002802 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002803 }
2804
2805 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2806 if (!sh) {
2807 printk(MYIOC_s_WARN_FMT
2808 "Unable to register controller with SCSI subsystem\n",
2809 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002810 error = -1;
2811 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002812 }
2813
2814 spin_lock_irqsave(&ioc->FreeQlock, flags);
2815
2816 /* Attach the SCSI Host to the IOC structure
2817 */
2818 ioc->sh = sh;
2819
2820 sh->io_port = 0;
2821 sh->n_io_port = 0;
2822 sh->irq = 0;
2823
2824 /* set 16 byte cdb's */
2825 sh->max_cmd_len = 16;
2826
Eric Moore793955f2007-01-29 09:42:20 -07002827 sh->max_id = ioc->pfacts[0].PortSCSIID;
2828 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002829
2830 sh->transportt = mptsas_transport_template;
2831
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002832 sh->this_id = ioc->pfacts[0].PortSCSIID;
2833
2834 /* Required entry.
2835 */
2836 sh->unique_id = ioc->id;
2837
2838 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002839 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002840 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002841 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002842 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002843
2844 /* Verify that we won't exceed the maximum
2845 * number of chain buffers
2846 * We can optimize: ZZ = req_sz/sizeof(SGE)
2847 * For 32bit SGE's:
2848 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2849 * + (req_sz - 64)/sizeof(SGE)
2850 * A slightly different algorithm is required for
2851 * 64bit SGEs.
2852 */
2853 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2854 if (sizeof(dma_addr_t) == sizeof(u64)) {
2855 numSGE = (scale - 1) *
2856 (ioc->facts.MaxChainDepth-1) + scale +
2857 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2858 sizeof(u32));
2859 } else {
2860 numSGE = 1 + (scale - 1) *
2861 (ioc->facts.MaxChainDepth-1) + scale +
2862 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2863 sizeof(u32));
2864 }
2865
2866 if (numSGE < sh->sg_tablesize) {
2867 /* Reset this value */
2868 dprintk((MYIOC_s_INFO_FMT
2869 "Resetting sg_tablesize to %d from %d\n",
2870 ioc->name, numSGE, sh->sg_tablesize));
2871 sh->sg_tablesize = numSGE;
2872 }
2873
2874 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2875
2876 hd = (MPT_SCSI_HOST *) sh->hostdata;
2877 hd->ioc = ioc;
2878
2879 /* SCSI needs scsi_cmnd lookup table!
2880 * (with size equal to req_depth*PtrSz!)
2881 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002882 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2883 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002884 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002885 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002886 }
2887
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002888 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2889 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002890
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002891 /* Clear the TM flags
2892 */
2893 hd->tmPending = 0;
2894 hd->tmState = TM_STATE_NONE;
2895 hd->resetPending = 0;
2896 hd->abortSCpnt = NULL;
2897
2898 /* Clear the pointer used to store
2899 * single-threaded commands, i.e., those
2900 * issued during a bus scan, dv and
2901 * configuration pages.
2902 */
2903 hd->cmdPtr = NULL;
2904
2905 /* Initialize this SCSI Hosts' timers
2906 * To use, set the timer expires field
2907 * and add_timer
2908 */
2909 init_timer(&hd->timer);
2910 hd->timer.data = (unsigned long) hd;
2911 hd->timer.function = mptscsih_timer_expired;
2912
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002913 ioc->sas_data.ptClear = mpt_pt_clear;
2914
2915 if (ioc->sas_data.ptClear==1) {
2916 mptbase_sas_persist_operation(
2917 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2918 }
2919
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002920 init_waitqueue_head(&hd->scandv_waitq);
2921 hd->scandv_wait_done = 0;
2922 hd->last_queue_full = 0;
2923
2924 error = scsi_add_host(sh, &ioc->pcidev->dev);
2925 if (error) {
2926 dprintk((KERN_ERR MYNAM
2927 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002928 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002929 }
2930
2931 mptsas_scan_sas_topology(ioc);
2932
2933 return 0;
2934
Eric Moore547f9a22006-06-27 14:42:12 -06002935 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002936
2937 mptscsih_remove(pdev);
2938 return error;
2939}
2940
2941static void __devexit mptsas_remove(struct pci_dev *pdev)
2942{
2943 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2944 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06002945 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002946
Eric Mooreb506ade2007-01-29 09:45:37 -07002947 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002948 sas_remove_host(ioc->sh);
2949
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002950 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002951 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2952 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002953 for (i = 0 ; i < p->num_phys ; i++)
2954 mptsas_port_delete(p->phy_info[i].port_details);
2955 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002956 kfree(p);
2957 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002958 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002959
2960 mptscsih_remove(pdev);
2961}
2962
2963static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06002964 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002965 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002966 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002967 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002968 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002969 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002970 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002971 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06002972 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002973 PCI_ANY_ID, PCI_ANY_ID },
2974 {0} /* Terminating entry */
2975};
2976MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2977
2978
2979static struct pci_driver mptsas_driver = {
2980 .name = "mptsas",
2981 .id_table = mptsas_pci_table,
2982 .probe = mptsas_probe,
2983 .remove = __devexit_p(mptsas_remove),
2984 .shutdown = mptscsih_shutdown,
2985#ifdef CONFIG_PM
2986 .suspend = mptscsih_suspend,
2987 .resume = mptscsih_resume,
2988#endif
2989};
2990
2991static int __init
2992mptsas_init(void)
2993{
2994 show_mptmod_ver(my_NAME, my_VERSION);
2995
2996 mptsas_transport_template =
2997 sas_attach_transport(&mptsas_transport_functions);
2998 if (!mptsas_transport_template)
2999 return -ENODEV;
3000
3001 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
3002 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
3003 mptsasInternalCtx =
3004 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003005 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003006
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003007 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07003008 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003009 ": Registered for IOC event notifications\n"));
3010 }
3011
3012 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
3013 dprintk((KERN_INFO MYNAM
3014 ": Registered for IOC reset notifications\n"));
3015 }
3016
3017 return pci_register_driver(&mptsas_driver);
3018}
3019
3020static void __exit
3021mptsas_exit(void)
3022{
3023 pci_unregister_driver(&mptsas_driver);
3024 sas_release_transport(mptsas_transport_template);
3025
3026 mpt_reset_deregister(mptsasDoneCtx);
3027 mpt_event_deregister(mptsasDoneCtx);
3028
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003029 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003030 mpt_deregister(mptsasInternalCtx);
3031 mpt_deregister(mptsasTaskCtx);
3032 mpt_deregister(mptsasDoneCtx);
3033}
3034
3035module_init(mptsas_init);
3036module_exit(mptsas_exit);