blob: 030bb8389aee90ebb91702e17751395ca926da6a [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 2005-2007 Dell
Christoph Hellwig0c33b272005-09-09 16:27:19 +02009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
64
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Christoph Hellwig0c33b272005-09-09 16:27:19 +020092static int mptsasDoneCtx = -1;
93static int mptsasTaskCtx = -1;
94static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020095static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020096
Eric Mooreb506ade2007-01-29 09:45:37 -070097static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Eric Mooredf9e0622007-01-29 09:46:21 -070099struct mptsas_target_reset_event {
100 struct list_head list;
101 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
102 u8 target_reset_issued;
103};
104
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100105enum mptsas_hotplug_action {
106 MPTSAS_ADD_DEVICE,
107 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -0700108 MPTSAS_ADD_RAID,
109 MPTSAS_DEL_RAID,
Eric Mooreb506ade2007-01-29 09:45:37 -0700110 MPTSAS_ADD_INACTIVE_VOLUME,
Moore, Ericbd23e942006-04-17 12:43:04 -0600111 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100112};
113
114struct mptsas_hotplug_event {
115 struct work_struct work;
116 MPT_ADAPTER *ioc;
117 enum mptsas_hotplug_action event_type;
118 u64 sas_address;
Eric Mooreb506ade2007-01-29 09:45:37 -0700119 u8 channel;
120 u8 id;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100121 u32 device_info;
122 u16 handle;
123 u16 parent_handle;
124 u8 phy_id;
Eric Mooreb506ade2007-01-29 09:45:37 -0700125 u8 phys_disk_num_valid; /* hrc (hidden raid component) */
126 u8 phys_disk_num; /* hrc - unique index*/
127 u8 hidden_raid_component; /* hrc - don't expose*/
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100128};
129
Moore, Erice6b2d762006-03-14 09:14:24 -0700130struct mptsas_discovery_event {
131 struct work_struct work;
132 MPT_ADAPTER *ioc;
133};
134
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200135/*
136 * SAS topology structures
137 *
138 * The MPT Fusion firmware interface spreads information about the
139 * SAS topology over many manufacture pages, thus we need some data
140 * structure to collect it and process it for the SAS transport class.
141 */
142
143struct mptsas_devinfo {
144 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700145 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100146 u16 handle_enclosure; /* enclosure identifier of the enclosure */
147 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200148 u8 phy_id; /* phy number of parent device */
149 u8 port_id; /* sas physical port this device
150 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100151 u8 id; /* logical target id of this device */
Eric Mooreb506ade2007-01-29 09:45:37 -0700152 u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100153 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200154 u64 sas_address; /* WWN of this device,
155 SATA is assigned by HBA,expander */
156 u32 device_info; /* bitfield detailed info about this device */
157};
158
Eric Moore547f9a22006-06-27 14:42:12 -0600159/*
160 * Specific details on ports, wide/narrow
161 */
162struct mptsas_portinfo_details{
Eric Moore547f9a22006-06-27 14:42:12 -0600163 u16 num_phys; /* number of phys belong to this port */
164 u64 phy_bitmask; /* TODO, extend support for 255 phys */
165 struct sas_rphy *rphy; /* transport layer rphy object */
166 struct sas_port *port; /* transport layer port object */
167 struct scsi_target *starget;
168 struct mptsas_portinfo *port_info;
169};
170
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200171struct mptsas_phyinfo {
Eric Moore2ecce492007-01-29 09:47:08 -0700172 u16 handle; /* unique id to address this */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200173 u8 phy_id; /* phy index */
Eric Moore547f9a22006-06-27 14:42:12 -0600174 u8 port_id; /* firmware port identifier */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200175 u8 negotiated_link_rate; /* nego'd link rate for this phy */
176 u8 hw_link_rate; /* hardware max/min phys link rate */
177 u8 programmed_link_rate; /* programmed max/min phy link rate */
Eric Moore547f9a22006-06-27 14:42:12 -0600178 u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200179 struct mptsas_devinfo identify; /* point to phy device info */
180 struct mptsas_devinfo attached; /* point to attached device info */
Eric Moore547f9a22006-06-27 14:42:12 -0600181 struct sas_phy *phy; /* transport layer phy object */
182 struct mptsas_portinfo *portinfo;
183 struct mptsas_portinfo_details * port_details;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200184};
185
186struct mptsas_portinfo {
187 struct list_head list;
Eric Moore547f9a22006-06-27 14:42:12 -0600188 u16 num_phys; /* number of phys */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200189 struct mptsas_phyinfo *phy_info;
190};
191
Christoph Hellwige3094442006-02-16 13:25:36 +0100192struct mptsas_enclosure {
193 u64 enclosure_logical_id; /* The WWN for the enclosure */
194 u16 enclosure_handle; /* unique id to address this */
195 u16 flags; /* details enclosure management */
196 u16 num_slot; /* num slots */
197 u16 start_slot; /* first slot */
198 u8 start_id; /* starting logical target id */
199 u8 start_channel; /* starting logical channel id */
200 u8 sep_id; /* SEP device logical target id */
201 u8 sep_channel; /* SEP channel logical channel id */
202};
203
Eric Moore547f9a22006-06-27 14:42:12 -0600204#ifdef MPT_DEBUG_SAS
Christoph Hellwigb5141122005-10-28 22:07:41 +0200205static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
206{
207 printk("---- IO UNIT PAGE 0 ------------\n");
208 printk("Handle=0x%X\n",
209 le16_to_cpu(phy_data->AttachedDeviceHandle));
210 printk("Controller Handle=0x%X\n",
211 le16_to_cpu(phy_data->ControllerDevHandle));
212 printk("Port=0x%X\n", phy_data->Port);
213 printk("Port Flags=0x%X\n", phy_data->PortFlags);
214 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
215 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
216 printk("Controller PHY Device Info=0x%X\n",
217 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
218 printk("DiscoveryStatus=0x%X\n",
219 le32_to_cpu(phy_data->DiscoveryStatus));
220 printk("\n");
221}
222
223static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
224{
225 __le64 sas_address;
226
227 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
228
229 printk("---- SAS PHY PAGE 0 ------------\n");
230 printk("Attached Device Handle=0x%X\n",
231 le16_to_cpu(pg0->AttachedDevHandle));
232 printk("SAS Address=0x%llX\n",
233 (unsigned long long)le64_to_cpu(sas_address));
234 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
235 printk("Attached Device Info=0x%X\n",
236 le32_to_cpu(pg0->AttachedDeviceInfo));
237 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
238 printk("Change Count=0x%X\n", pg0->ChangeCount);
239 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
240 printk("\n");
241}
242
243static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
244{
245 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200246 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
247 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200249 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
250 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
251 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252}
253
254static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
255{
256 __le64 sas_address;
257
258 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
259
260 printk("---- SAS DEVICE PAGE 0 ---------\n");
261 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100262 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200263 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
264 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
Eric Mooref99be432007-01-04 20:46:54 -0700265 printk("SAS Address=0x%llX\n", (unsigned long long)
266 le64_to_cpu(sas_address));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200267 printk("Target ID=0x%X\n", pg0->TargetID);
268 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200269 /* The PhyNum field specifies the PHY number of the parent
270 * device this device is linked to
271 */
272 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
273 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200274 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
275 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
276 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
277 printk("\n");
278}
279
280static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
281{
282 printk("---- SAS EXPANDER PAGE 1 ------------\n");
283
284 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200285 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200286 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
287 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
288 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
289 printk("Owner Device Handle=0x%X\n",
290 le16_to_cpu(pg1->OwnerDevHandle));
291 printk("Attached Device Handle=0x%X\n",
292 le16_to_cpu(pg1->AttachedDevHandle));
293}
294#else
295#define mptsas_print_phy_data(phy_data) do { } while (0)
296#define mptsas_print_phy_pg0(pg0) do { } while (0)
297#define mptsas_print_phy_pg1(pg1) do { } while (0)
298#define mptsas_print_device_pg0(pg0) do { } while (0)
299#define mptsas_print_expander_pg1(pg1) do { } while (0)
300#endif
301
Christoph Hellwige3094442006-02-16 13:25:36 +0100302static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
303{
304 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
305 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
306}
307
308static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
309{
310 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
311 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
312}
313
Moore, Erice6b2d762006-03-14 09:14:24 -0700314/*
315 * mptsas_find_portinfo_by_handle
316 *
317 * This function should be called with the sas_topology_mutex already held
318 */
319static struct mptsas_portinfo *
320mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
321{
322 struct mptsas_portinfo *port_info, *rc=NULL;
323 int i;
324
325 list_for_each_entry(port_info, &ioc->sas_topology, list)
326 for (i = 0; i < port_info->num_phys; i++)
327 if (port_info->phy_info[i].identify.handle == handle) {
328 rc = port_info;
329 goto out;
330 }
331 out:
332 return rc;
333}
334
Moore, Ericbd23e942006-04-17 12:43:04 -0600335/*
336 * Returns true if there is a scsi end device
337 */
338static inline int
339mptsas_is_end_device(struct mptsas_devinfo * attached)
340{
Eric Moore547f9a22006-06-27 14:42:12 -0600341 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600342 (attached->device_info &
343 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
344 ((attached->device_info &
345 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
346 (attached->device_info &
347 MPI_SAS_DEVICE_INFO_STP_TARGET) |
348 (attached->device_info &
349 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
350 return 1;
351 else
352 return 0;
353}
354
Eric Moore547f9a22006-06-27 14:42:12 -0600355/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600356static void
Eric Moore547f9a22006-06-27 14:42:12 -0600357mptsas_port_delete(struct mptsas_portinfo_details * port_details)
358{
359 struct mptsas_portinfo *port_info;
360 struct mptsas_phyinfo *phy_info;
361 u8 i;
362
363 if (!port_details)
364 return;
365
366 port_info = port_details->port_info;
367 phy_info = port_info->phy_info;
368
Eric Mooredc22f162006-07-06 11:23:14 -0600369 dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700370 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
371 port_details->num_phys, (unsigned long long)
372 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600373
374 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
375 if(phy_info->port_details != port_details)
376 continue;
377 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
378 phy_info->port_details = NULL;
379 }
380 kfree(port_details);
381}
382
383static inline struct sas_rphy *
384mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
385{
386 if (phy_info->port_details)
387 return phy_info->port_details->rphy;
388 else
389 return NULL;
390}
391
392static inline void
393mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
394{
395 if (phy_info->port_details) {
396 phy_info->port_details->rphy = rphy;
397 dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
398 }
399
400#ifdef MPT_DEBUG_SAS_WIDE
401 if (rphy) {
402 dev_printk(KERN_DEBUG, &rphy->dev, "add:");
403 printk("rphy=%p release=%p\n",
404 rphy, rphy->dev.release);
405 }
406#endif
407}
408
409static inline struct sas_port *
410mptsas_get_port(struct mptsas_phyinfo *phy_info)
411{
412 if (phy_info->port_details)
413 return phy_info->port_details->port;
414 else
415 return NULL;
416}
417
418static inline void
419mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
420{
421 if (phy_info->port_details)
422 phy_info->port_details->port = port;
423
424#ifdef MPT_DEBUG_SAS_WIDE
425 if (port) {
426 dev_printk(KERN_DEBUG, &port->dev, "add: ");
427 printk("port=%p release=%p\n",
428 port, port->dev.release);
429 }
430#endif
431}
432
433static inline struct scsi_target *
434mptsas_get_starget(struct mptsas_phyinfo *phy_info)
435{
436 if (phy_info->port_details)
437 return phy_info->port_details->starget;
438 else
439 return NULL;
440}
441
442static inline void
443mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
444starget)
445{
446 if (phy_info->port_details)
447 phy_info->port_details->starget = starget;
448}
449
450
451/*
452 * mptsas_setup_wide_ports
453 *
454 * Updates for new and existing narrow/wide port configuration
455 * in the sas_topology
456 */
Eric Moore376ac832006-06-29 17:36:26 -0600457static void
Eric Moore547f9a22006-06-27 14:42:12 -0600458mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
459{
460 struct mptsas_portinfo_details * port_details;
461 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
462 u64 sas_address;
463 int i, j;
464
465 mutex_lock(&ioc->sas_topology_mutex);
466
467 phy_info = port_info->phy_info;
468 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
469 if (phy_info->attached.handle)
470 continue;
471 port_details = phy_info->port_details;
472 if (!port_details)
473 continue;
474 if (port_details->num_phys < 2)
475 continue;
476 /*
477 * Removing a phy from a port, letting the last
478 * phy be removed by firmware events.
479 */
480 dsaswideprintk((KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600481 "%s: [%p]: deleting phy = %d\n",
482 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600483 port_details->num_phys--;
484 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
485 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
486 sas_port_delete_phy(port_details->port, phy_info->phy);
487 phy_info->port_details = NULL;
488 }
489
490 /*
491 * Populate and refresh the tree
492 */
493 phy_info = port_info->phy_info;
494 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
495 sas_address = phy_info->attached.sas_address;
496 dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700497 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600498 if (!sas_address)
499 continue;
500 port_details = phy_info->port_details;
501 /*
502 * Forming a port
503 */
504 if (!port_details) {
505 port_details = kzalloc(sizeof(*port_details),
506 GFP_KERNEL);
507 if (!port_details)
508 goto out;
509 port_details->num_phys = 1;
510 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600511 if (phy_info->phy_id < 64 )
512 port_details->phy_bitmask |=
513 (1 << phy_info->phy_id);
514 phy_info->sas_port_add_phy=1;
515 dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700516 "phy_id=%d sas_address=0x%018llX\n",
517 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600518 phy_info->port_details = port_details;
519 }
520
521 if (i == port_info->num_phys - 1)
522 continue;
523 phy_info_cmp = &port_info->phy_info[i + 1];
524 for (j = i + 1 ; j < port_info->num_phys ; j++,
525 phy_info_cmp++) {
526 if (!phy_info_cmp->attached.sas_address)
527 continue;
528 if (sas_address != phy_info_cmp->attached.sas_address)
529 continue;
530 if (phy_info_cmp->port_details == port_details )
531 continue;
532 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700533 "\t\tphy_id=%d sas_address=0x%018llX\n",
534 j, (unsigned long long)
535 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600536 if (phy_info_cmp->port_details) {
537 port_details->rphy =
538 mptsas_get_rphy(phy_info_cmp);
539 port_details->port =
540 mptsas_get_port(phy_info_cmp);
541 port_details->starget =
542 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600543 port_details->num_phys =
544 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600545 if (!phy_info_cmp->port_details->num_phys)
546 kfree(phy_info_cmp->port_details);
547 } else
548 phy_info_cmp->sas_port_add_phy=1;
549 /*
550 * Adding a phy to a port
551 */
552 phy_info_cmp->port_details = port_details;
553 if (phy_info_cmp->phy_id < 64 )
554 port_details->phy_bitmask |=
555 (1 << phy_info_cmp->phy_id);
556 port_details->num_phys++;
557 }
558 }
559
560 out:
561
562#ifdef MPT_DEBUG_SAS_WIDE
563 for (i = 0; i < port_info->num_phys; i++) {
564 port_details = port_info->phy_info[i].port_details;
565 if (!port_details)
566 continue;
567 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700568 "%s: [%p]: phy_id=%02d num_phys=%02d "
569 "bitmask=0x%016llX\n", __FUNCTION__,
570 port_details, i, port_details->num_phys,
571 (unsigned long long)port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600572 dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
573 port_details->port, port_details->rphy));
574 }
575 dsaswideprintk((KERN_DEBUG"\n"));
576#endif
577 mutex_unlock(&ioc->sas_topology_mutex);
578}
579
Eric Mooredf9e0622007-01-29 09:46:21 -0700580/**
581 * csmisas_find_vtarget
582 *
583 * @ioc
584 * @volume_id
585 * @volume_bus
586 *
587 **/
588static VirtTarget *
589mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600590{
Eric Mooredf9e0622007-01-29 09:46:21 -0700591 struct scsi_device *sdev;
592 VirtDevice *vdev;
593 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600594
Eric Mooredf9e0622007-01-29 09:46:21 -0700595 shost_for_each_device(sdev, ioc->sh) {
596 if ((vdev = sdev->hostdata) == NULL)
597 continue;
598 if (vdev->vtarget->id == id &&
599 vdev->vtarget->channel == channel)
600 vtarget = vdev->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600601 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700602 return vtarget;
603}
604
605/**
606 * mptsas_target_reset
607 *
608 * Issues TARGET_RESET to end device using handshaking method
609 *
610 * @ioc
611 * @channel
612 * @id
613 *
614 * Returns (1) success
615 * (0) failure
616 *
617 **/
618static int
619mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
620{
621 MPT_FRAME_HDR *mf;
622 SCSITaskMgmt_t *pScsiTm;
623
624 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
625 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
626 ioc->name,__FUNCTION__, __LINE__));
627 return 0;
628 }
629
630 /* Format the Request
631 */
632 pScsiTm = (SCSITaskMgmt_t *) mf;
633 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
634 pScsiTm->TargetID = id;
635 pScsiTm->Bus = channel;
636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
637 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
638 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
639
640 DBG_DUMP_TM_REQUEST_FRAME(mf);
641
642 if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
643 sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
644 mpt_free_msg_frame(ioc, mf);
645 dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
646 ioc->name,__FUNCTION__, __LINE__));
647 return 0;
648 }
649
650 return 1;
651}
652
653/**
654 * mptsas_target_reset_queue
655 *
656 * Receive request for TARGET_RESET after recieving an firmware
657 * event NOT_RESPONDING_EVENT, then put command in link list
658 * and queue if task_queue already in use.
659 *
660 * @ioc
661 * @sas_event_data
662 *
663 **/
664static void
665mptsas_target_reset_queue(MPT_ADAPTER *ioc,
666 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
667{
668 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
669 VirtTarget *vtarget = NULL;
670 struct mptsas_target_reset_event *target_reset_list;
671 u8 id, channel;
672
673 id = sas_event_data->TargetID;
674 channel = sas_event_data->Bus;
675
676 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
677 return;
678
679 vtarget->deleted = 1; /* block IO */
680
681 target_reset_list = kzalloc(sizeof(*target_reset_list),
682 GFP_ATOMIC);
683 if (!target_reset_list) {
684 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
685 ioc->name,__FUNCTION__, __LINE__));
686 return;
687 }
688
689 memcpy(&target_reset_list->sas_event_data, sas_event_data,
690 sizeof(*sas_event_data));
691 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
692
693 if (hd->resetPending)
694 return;
695
696 if (mptsas_target_reset(ioc, channel, id)) {
697 target_reset_list->target_reset_issued = 1;
698 hd->resetPending = 1;
699 }
700}
701
702/**
703 * mptsas_dev_reset_complete
704 *
705 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
706 * enable work queue to finish off removing device from upper layers.
707 * then send next TARGET_RESET in the queue.
708 *
709 * @ioc
710 *
711 **/
712static void
713mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
714{
715 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
716 struct list_head *head = &hd->target_reset_list;
717 struct mptsas_target_reset_event *target_reset_list;
718 struct mptsas_hotplug_event *ev;
719 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
720 u8 id, channel;
721 __le64 sas_address;
722
723 if (list_empty(head))
724 return;
725
726 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
727
728 sas_event_data = &target_reset_list->sas_event_data;
729 id = sas_event_data->TargetID;
730 channel = sas_event_data->Bus;
731 hd->resetPending = 0;
732
733 /*
734 * retry target reset
735 */
736 if (!target_reset_list->target_reset_issued) {
737 if (mptsas_target_reset(ioc, channel, id)) {
738 target_reset_list->target_reset_issued = 1;
739 hd->resetPending = 1;
740 }
741 return;
742 }
743
744 /*
745 * enable work queue to remove device from upper layers
746 */
747 list_del(&target_reset_list->list);
748
749 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
750 if (!ev) {
751 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
752 ioc->name,__FUNCTION__, __LINE__));
753 return;
754 }
755
756 INIT_WORK(&ev->work, mptsas_hotplug_work);
757 ev->ioc = ioc;
758 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
759 ev->parent_handle =
760 le16_to_cpu(sas_event_data->ParentDevHandle);
761 ev->channel = channel;
762 ev->id =id;
763 ev->phy_id = sas_event_data->PhyNum;
764 memcpy(&sas_address, &sas_event_data->SASAddress,
765 sizeof(__le64));
766 ev->sas_address = le64_to_cpu(sas_address);
767 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
768 ev->event_type = MPTSAS_DEL_DEVICE;
769 schedule_work(&ev->work);
770 kfree(target_reset_list);
771
772 /*
773 * issue target reset to next device in the queue
774 */
775
776 head = &hd->target_reset_list;
777 if (list_empty(head))
778 return;
779
780 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
781 list);
782
783 sas_event_data = &target_reset_list->sas_event_data;
784 id = sas_event_data->TargetID;
785 channel = sas_event_data->Bus;
786
787 if (mptsas_target_reset(ioc, channel, id)) {
788 target_reset_list->target_reset_issued = 1;
789 hd->resetPending = 1;
790 }
791}
792
793/**
794 * mptsas_taskmgmt_complete
795 *
796 * @ioc
797 * @mf
798 * @mr
799 *
800 **/
801static int
802mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
803{
804 mptsas_dev_reset_complete(ioc);
805 return mptscsih_taskmgmt_complete(ioc, mf, mr);
806}
807
808/**
809 * mptscsih_ioc_reset
810 *
811 * @ioc
812 * @reset_phase
813 *
814 **/
815static int
816mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
817{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800818 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700819 struct mptsas_target_reset_event *target_reset_list, *n;
820 int rc;
821
822 rc = mptscsih_ioc_reset(ioc, reset_phase);
823
824 if (ioc->bus_type != SAS)
825 goto out;
826
827 if (reset_phase != MPT_IOC_POST_RESET)
828 goto out;
829
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800830 if (!ioc->sh || !ioc->sh->hostdata)
831 goto out;
832 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
833 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700834 goto out;
835
836 if (list_empty(&hd->target_reset_list))
837 goto out;
838
839 /* flush the target_reset_list */
840 list_for_each_entry_safe(target_reset_list, n,
841 &hd->target_reset_list, list) {
842 list_del(&target_reset_list->list);
843 kfree(target_reset_list);
844 }
845
846 out:
847 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600848}
849
Christoph Hellwige3094442006-02-16 13:25:36 +0100850static int
Moore, Eric52435432006-03-14 09:14:15 -0700851mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100852 u32 form, u32 form_specific)
853{
854 ConfigExtendedPageHeader_t hdr;
855 CONFIGPARMS cfg;
856 SasEnclosurePage0_t *buffer;
857 dma_addr_t dma_handle;
858 int error;
859 __le64 le_identifier;
860
861 memset(&hdr, 0, sizeof(hdr));
862 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
863 hdr.PageNumber = 0;
864 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
865 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
866
867 cfg.cfghdr.ehdr = &hdr;
868 cfg.physAddr = -1;
869 cfg.pageAddr = form + form_specific;
870 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
871 cfg.dir = 0; /* read */
872 cfg.timeout = 10;
873
874 error = mpt_config(ioc, &cfg);
875 if (error)
876 goto out;
877 if (!hdr.ExtPageLength) {
878 error = -ENXIO;
879 goto out;
880 }
881
882 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
883 &dma_handle);
884 if (!buffer) {
885 error = -ENOMEM;
886 goto out;
887 }
888
889 cfg.physAddr = dma_handle;
890 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
891
892 error = mpt_config(ioc, &cfg);
893 if (error)
894 goto out_free_consistent;
895
896 /* save config data */
897 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
898 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
899 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
900 enclosure->flags = le16_to_cpu(buffer->Flags);
901 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
902 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
903 enclosure->start_id = buffer->StartTargetID;
904 enclosure->start_channel = buffer->StartBus;
905 enclosure->sep_id = buffer->SEPTargetID;
906 enclosure->sep_channel = buffer->SEPBus;
907
908 out_free_consistent:
909 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
910 buffer, dma_handle);
911 out:
912 return error;
913}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200914
James Bottomleyf013db32006-03-18 14:54:36 -0600915static int
916mptsas_slave_configure(struct scsi_device *sdev)
917{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600918
James Bottomleye8bf3942006-07-11 17:49:34 -0400919 if (sdev->channel == MPTSAS_RAID_CHANNEL)
920 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600921
James Bottomleye8bf3942006-07-11 17:49:34 -0400922 sas_read_port_mode_page(sdev);
923
924 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600925 return mptscsih_slave_configure(sdev);
926}
927
Eric Moore547f9a22006-06-27 14:42:12 -0600928static int
929mptsas_target_alloc(struct scsi_target *starget)
930{
931 struct Scsi_Host *host = dev_to_shost(&starget->dev);
932 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
933 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700934 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600935 struct sas_rphy *rphy;
936 struct mptsas_portinfo *p;
937 int i;
938
939 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
940 if (!vtarget)
941 return -ENOMEM;
942
943 vtarget->starget = starget;
944 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700945 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
946 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600947 channel = 0;
948
Eric Moore793955f2007-01-29 09:42:20 -0700949 /*
950 * RAID volumes placed beyond the last expected port.
951 */
952 if (starget->channel == MPTSAS_RAID_CHANNEL) {
953 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
954 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
955 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600956 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700957 }
Eric Moore547f9a22006-06-27 14:42:12 -0600958
959 rphy = dev_to_rphy(starget->dev.parent);
960 mutex_lock(&hd->ioc->sas_topology_mutex);
961 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
962 for (i = 0; i < p->num_phys; i++) {
963 if (p->phy_info[i].attached.sas_address !=
964 rphy->identify.sas_address)
965 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700966 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600967 channel = p->phy_info[i].attached.channel;
968 mptsas_set_starget(&p->phy_info[i], starget);
969
970 /*
971 * Exposing hidden raid components
972 */
Eric Moore793955f2007-01-29 09:42:20 -0700973 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
974 id = mptscsih_raid_id_to_num(hd->ioc,
975 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600976 vtarget->tflags |=
977 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700978 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600979 }
980 mutex_unlock(&hd->ioc->sas_topology_mutex);
981 goto out;
982 }
983 }
984 mutex_unlock(&hd->ioc->sas_topology_mutex);
985
986 kfree(vtarget);
987 return -ENXIO;
988
989 out:
Eric Moore793955f2007-01-29 09:42:20 -0700990 vtarget->id = id;
991 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600992 starget->hostdata = vtarget;
993 return 0;
994}
995
996static void
997mptsas_target_destroy(struct scsi_target *starget)
998{
999 struct Scsi_Host *host = dev_to_shost(&starget->dev);
1000 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1001 struct sas_rphy *rphy;
1002 struct mptsas_portinfo *p;
1003 int i;
1004
1005 if (!starget->hostdata)
1006 return;
1007
James Bottomleye8bf3942006-07-11 17:49:34 -04001008 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001009 goto out;
1010
1011 rphy = dev_to_rphy(starget->dev.parent);
1012 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1013 for (i = 0; i < p->num_phys; i++) {
1014 if (p->phy_info[i].attached.sas_address !=
1015 rphy->identify.sas_address)
1016 continue;
1017 mptsas_set_starget(&p->phy_info[i], NULL);
1018 goto out;
1019 }
1020 }
1021
1022 out:
1023 kfree(starget->hostdata);
1024 starget->hostdata = NULL;
1025}
1026
1027
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001028static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001029mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001030{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001031 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001032 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1033 struct sas_rphy *rphy;
1034 struct mptsas_portinfo *p;
1035 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001036 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001037 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001038
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001039 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001040 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -06001041 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001042 hd->ioc->name, sizeof(VirtDevice));
1043 return -ENOMEM;
1044 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001045 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -06001046 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001047
James Bottomleye8bf3942006-07-11 17:49:34 -04001048 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001049 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001050
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001051 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001052 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001053 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1054 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001055 if (p->phy_info[i].attached.sas_address !=
1056 rphy->identify.sas_address)
1057 continue;
1058 vdev->lun = sdev->lun;
1059 /*
1060 * Exposing hidden raid components
1061 */
1062 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001063 p->phy_info[i].attached.channel,
1064 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001065 sdev->no_uld_attach = 1;
1066 mutex_unlock(&hd->ioc->sas_topology_mutex);
1067 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001068 }
1069 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001070 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001071
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001072 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001073 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001074
1075 out:
Eric Moore547f9a22006-06-27 14:42:12 -06001076 vdev->vtarget->num_luns++;
1077 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001078 return 0;
1079}
1080
Eric Moore547f9a22006-06-27 14:42:12 -06001081static int
1082mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001083{
Eric Moore547f9a22006-06-27 14:42:12 -06001084 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001085
Eric Moore793955f2007-01-29 09:42:20 -07001086 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001087 SCpnt->result = DID_NO_CONNECT << 16;
1088 done(SCpnt);
1089 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001090 }
Eric Moore547f9a22006-06-27 14:42:12 -06001091
Eric Moore793955f2007-01-29 09:42:20 -07001092// scsi_print_command(SCpnt);
1093
Eric Moore547f9a22006-06-27 14:42:12 -06001094 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001095}
1096
Eric Moore547f9a22006-06-27 14:42:12 -06001097
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001098static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001099 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001100 .proc_name = "mptsas",
1101 .proc_info = mptscsih_proc_info,
1102 .name = "MPT SPI Host",
1103 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001104 .queuecommand = mptsas_qcmd,
1105 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001106 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001107 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001108 .target_destroy = mptsas_target_destroy,
1109 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001110 .change_queue_depth = mptscsih_change_queue_depth,
1111 .eh_abort_handler = mptscsih_abort,
1112 .eh_device_reset_handler = mptscsih_dev_reset,
1113 .eh_bus_reset_handler = mptscsih_bus_reset,
1114 .eh_host_reset_handler = mptscsih_host_reset,
1115 .bios_param = mptscsih_bios_param,
1116 .can_queue = MPT_FC_CAN_QUEUE,
1117 .this_id = -1,
1118 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1119 .max_sectors = 8192,
1120 .cmd_per_lun = 7,
1121 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301122 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001123};
1124
Christoph Hellwigb5141122005-10-28 22:07:41 +02001125static int mptsas_get_linkerrors(struct sas_phy *phy)
1126{
1127 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1128 ConfigExtendedPageHeader_t hdr;
1129 CONFIGPARMS cfg;
1130 SasPhyPage1_t *buffer;
1131 dma_addr_t dma_handle;
1132 int error;
1133
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001134 /* FIXME: only have link errors on local phys */
1135 if (!scsi_is_sas_phy_local(phy))
1136 return -EINVAL;
1137
Christoph Hellwigb5141122005-10-28 22:07:41 +02001138 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1139 hdr.ExtPageLength = 0;
1140 hdr.PageNumber = 1 /* page number 1*/;
1141 hdr.Reserved1 = 0;
1142 hdr.Reserved2 = 0;
1143 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1144 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1145
1146 cfg.cfghdr.ehdr = &hdr;
1147 cfg.physAddr = -1;
1148 cfg.pageAddr = phy->identify.phy_identifier;
1149 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1150 cfg.dir = 0; /* read */
1151 cfg.timeout = 10;
1152
1153 error = mpt_config(ioc, &cfg);
1154 if (error)
1155 return error;
1156 if (!hdr.ExtPageLength)
1157 return -ENXIO;
1158
1159 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1160 &dma_handle);
1161 if (!buffer)
1162 return -ENOMEM;
1163
1164 cfg.physAddr = dma_handle;
1165 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1166
1167 error = mpt_config(ioc, &cfg);
1168 if (error)
1169 goto out_free_consistent;
1170
1171 mptsas_print_phy_pg1(buffer);
1172
1173 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1174 phy->running_disparity_error_count =
1175 le32_to_cpu(buffer->RunningDisparityErrorCount);
1176 phy->loss_of_dword_sync_count =
1177 le32_to_cpu(buffer->LossDwordSynchCount);
1178 phy->phy_reset_problem_count =
1179 le32_to_cpu(buffer->PhyResetProblemCount);
1180
1181 out_free_consistent:
1182 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1183 buffer, dma_handle);
1184 return error;
1185}
1186
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001187static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1188 MPT_FRAME_HDR *reply)
1189{
1190 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1191 if (reply != NULL) {
1192 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1193 memcpy(ioc->sas_mgmt.reply, reply,
1194 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1195 }
1196 complete(&ioc->sas_mgmt.done);
1197 return 1;
1198}
1199
1200static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1201{
1202 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1203 SasIoUnitControlRequest_t *req;
1204 SasIoUnitControlReply_t *reply;
1205 MPT_FRAME_HDR *mf;
1206 MPIHeader_t *hdr;
1207 unsigned long timeleft;
1208 int error = -ERESTARTSYS;
1209
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001210 /* FIXME: fusion doesn't allow non-local phy reset */
1211 if (!scsi_is_sas_phy_local(phy))
1212 return -EINVAL;
1213
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001214 /* not implemented for expanders */
1215 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1216 return -ENXIO;
1217
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001218 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001219 goto out;
1220
1221 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1222 if (!mf) {
1223 error = -ENOMEM;
1224 goto out_unlock;
1225 }
1226
1227 hdr = (MPIHeader_t *) mf;
1228 req = (SasIoUnitControlRequest_t *)mf;
1229 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1230 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1231 req->MsgContext = hdr->MsgContext;
1232 req->Operation = hard_reset ?
1233 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1234 req->PhyNum = phy->identify.phy_identifier;
1235
1236 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1237
1238 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1239 10 * HZ);
1240 if (!timeleft) {
1241 /* On timeout reset the board */
1242 mpt_free_msg_frame(ioc, mf);
1243 mpt_HardResetHandler(ioc, CAN_SLEEP);
1244 error = -ETIMEDOUT;
1245 goto out_unlock;
1246 }
1247
1248 /* a reply frame is expected */
1249 if ((ioc->sas_mgmt.status &
1250 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1251 error = -ENXIO;
1252 goto out_unlock;
1253 }
1254
1255 /* process the completed Reply Message Frame */
1256 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1257 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1258 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1259 __FUNCTION__,
1260 reply->IOCStatus,
1261 reply->IOCLogInfo);
1262 error = -ENXIO;
1263 goto out_unlock;
1264 }
1265
1266 error = 0;
1267
1268 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001269 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001270 out:
1271 return error;
1272}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001273
Christoph Hellwige3094442006-02-16 13:25:36 +01001274static int
1275mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1276{
1277 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1278 int i, error;
1279 struct mptsas_portinfo *p;
1280 struct mptsas_enclosure enclosure_info;
1281 u64 enclosure_handle;
1282
1283 mutex_lock(&ioc->sas_topology_mutex);
1284 list_for_each_entry(p, &ioc->sas_topology, list) {
1285 for (i = 0; i < p->num_phys; i++) {
1286 if (p->phy_info[i].attached.sas_address ==
1287 rphy->identify.sas_address) {
1288 enclosure_handle = p->phy_info[i].
1289 attached.handle_enclosure;
1290 goto found_info;
1291 }
1292 }
1293 }
1294 mutex_unlock(&ioc->sas_topology_mutex);
1295 return -ENXIO;
1296
1297 found_info:
1298 mutex_unlock(&ioc->sas_topology_mutex);
1299 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001300 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001301 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1302 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1303 if (!error)
1304 *identifier = enclosure_info.enclosure_logical_id;
1305 return error;
1306}
1307
1308static int
1309mptsas_get_bay_identifier(struct sas_rphy *rphy)
1310{
1311 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1312 struct mptsas_portinfo *p;
1313 int i, rc;
1314
1315 mutex_lock(&ioc->sas_topology_mutex);
1316 list_for_each_entry(p, &ioc->sas_topology, list) {
1317 for (i = 0; i < p->num_phys; i++) {
1318 if (p->phy_info[i].attached.sas_address ==
1319 rphy->identify.sas_address) {
1320 rc = p->phy_info[i].attached.slot;
1321 goto out;
1322 }
1323 }
1324 }
1325 rc = -ENXIO;
1326 out:
1327 mutex_unlock(&ioc->sas_topology_mutex);
1328 return rc;
1329}
1330
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001331static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001332 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001333 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1334 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001335 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001336};
1337
1338static struct scsi_transport_template *mptsas_transport_template;
1339
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001340static int
1341mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1342{
1343 ConfigExtendedPageHeader_t hdr;
1344 CONFIGPARMS cfg;
1345 SasIOUnitPage0_t *buffer;
1346 dma_addr_t dma_handle;
1347 int error, i;
1348
1349 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1350 hdr.ExtPageLength = 0;
1351 hdr.PageNumber = 0;
1352 hdr.Reserved1 = 0;
1353 hdr.Reserved2 = 0;
1354 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1355 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1356
1357 cfg.cfghdr.ehdr = &hdr;
1358 cfg.physAddr = -1;
1359 cfg.pageAddr = 0;
1360 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1361 cfg.dir = 0; /* read */
1362 cfg.timeout = 10;
1363
1364 error = mpt_config(ioc, &cfg);
1365 if (error)
1366 goto out;
1367 if (!hdr.ExtPageLength) {
1368 error = -ENXIO;
1369 goto out;
1370 }
1371
1372 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1373 &dma_handle);
1374 if (!buffer) {
1375 error = -ENOMEM;
1376 goto out;
1377 }
1378
1379 cfg.physAddr = dma_handle;
1380 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1381
1382 error = mpt_config(ioc, &cfg);
1383 if (error)
1384 goto out_free_consistent;
1385
1386 port_info->num_phys = buffer->NumPhys;
1387 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001388 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001389 if (!port_info->phy_info) {
1390 error = -ENOMEM;
1391 goto out_free_consistent;
1392 }
1393
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301394 ioc->nvdata_version_persistent =
1395 le16_to_cpu(buffer->NvdataVersionPersistent);
1396 ioc->nvdata_version_default =
1397 le16_to_cpu(buffer->NvdataVersionDefault);
1398
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001399 for (i = 0; i < port_info->num_phys; i++) {
1400 mptsas_print_phy_data(&buffer->PhyData[i]);
1401 port_info->phy_info[i].phy_id = i;
1402 port_info->phy_info[i].port_id =
1403 buffer->PhyData[i].Port;
1404 port_info->phy_info[i].negotiated_link_rate =
1405 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001406 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001407 port_info->phy_info[i].handle =
1408 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001409 }
1410
1411 out_free_consistent:
1412 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1413 buffer, dma_handle);
1414 out:
1415 return error;
1416}
1417
1418static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301419mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1420{
1421 ConfigExtendedPageHeader_t hdr;
1422 CONFIGPARMS cfg;
1423 SasIOUnitPage1_t *buffer;
1424 dma_addr_t dma_handle;
1425 int error;
1426 u16 device_missing_delay;
1427
1428 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1429 memset(&cfg, 0, sizeof(CONFIGPARMS));
1430
1431 cfg.cfghdr.ehdr = &hdr;
1432 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1433 cfg.timeout = 10;
1434 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1435 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1436 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1437 cfg.cfghdr.ehdr->PageNumber = 1;
1438
1439 error = mpt_config(ioc, &cfg);
1440 if (error)
1441 goto out;
1442 if (!hdr.ExtPageLength) {
1443 error = -ENXIO;
1444 goto out;
1445 }
1446
1447 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1448 &dma_handle);
1449 if (!buffer) {
1450 error = -ENOMEM;
1451 goto out;
1452 }
1453
1454 cfg.physAddr = dma_handle;
1455 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1456
1457 error = mpt_config(ioc, &cfg);
1458 if (error)
1459 goto out_free_consistent;
1460
1461 ioc->io_missing_delay =
1462 le16_to_cpu(buffer->IODeviceMissingDelay);
1463 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1464 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1465 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1466 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1467
1468 out_free_consistent:
1469 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1470 buffer, dma_handle);
1471 out:
1472 return error;
1473}
1474
1475static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001476mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1477 u32 form, u32 form_specific)
1478{
1479 ConfigExtendedPageHeader_t hdr;
1480 CONFIGPARMS cfg;
1481 SasPhyPage0_t *buffer;
1482 dma_addr_t dma_handle;
1483 int error;
1484
1485 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1486 hdr.ExtPageLength = 0;
1487 hdr.PageNumber = 0;
1488 hdr.Reserved1 = 0;
1489 hdr.Reserved2 = 0;
1490 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1491 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1492
1493 cfg.cfghdr.ehdr = &hdr;
1494 cfg.dir = 0; /* read */
1495 cfg.timeout = 10;
1496
1497 /* Get Phy Pg 0 for each Phy. */
1498 cfg.physAddr = -1;
1499 cfg.pageAddr = form + form_specific;
1500 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1501
1502 error = mpt_config(ioc, &cfg);
1503 if (error)
1504 goto out;
1505
1506 if (!hdr.ExtPageLength) {
1507 error = -ENXIO;
1508 goto out;
1509 }
1510
1511 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1512 &dma_handle);
1513 if (!buffer) {
1514 error = -ENOMEM;
1515 goto out;
1516 }
1517
1518 cfg.physAddr = dma_handle;
1519 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1520
1521 error = mpt_config(ioc, &cfg);
1522 if (error)
1523 goto out_free_consistent;
1524
1525 mptsas_print_phy_pg0(buffer);
1526
1527 phy_info->hw_link_rate = buffer->HwLinkRate;
1528 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1529 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1530 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1531
1532 out_free_consistent:
1533 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1534 buffer, dma_handle);
1535 out:
1536 return error;
1537}
1538
1539static int
1540mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1541 u32 form, u32 form_specific)
1542{
1543 ConfigExtendedPageHeader_t hdr;
1544 CONFIGPARMS cfg;
1545 SasDevicePage0_t *buffer;
1546 dma_addr_t dma_handle;
1547 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001548 int error=0;
1549
1550 if (ioc->sas_discovery_runtime &&
1551 mptsas_is_end_device(device_info))
1552 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001553
1554 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1555 hdr.ExtPageLength = 0;
1556 hdr.PageNumber = 0;
1557 hdr.Reserved1 = 0;
1558 hdr.Reserved2 = 0;
1559 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1560 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1561
1562 cfg.cfghdr.ehdr = &hdr;
1563 cfg.pageAddr = form + form_specific;
1564 cfg.physAddr = -1;
1565 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1566 cfg.dir = 0; /* read */
1567 cfg.timeout = 10;
1568
Moore, Ericdb9c9172006-03-14 09:14:18 -07001569 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001570 error = mpt_config(ioc, &cfg);
1571 if (error)
1572 goto out;
1573 if (!hdr.ExtPageLength) {
1574 error = -ENXIO;
1575 goto out;
1576 }
1577
1578 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1579 &dma_handle);
1580 if (!buffer) {
1581 error = -ENOMEM;
1582 goto out;
1583 }
1584
1585 cfg.physAddr = dma_handle;
1586 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1587
1588 error = mpt_config(ioc, &cfg);
1589 if (error)
1590 goto out_free_consistent;
1591
1592 mptsas_print_device_pg0(buffer);
1593
1594 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001595 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001596 device_info->handle_enclosure =
1597 le16_to_cpu(buffer->EnclosureHandle);
1598 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001599 device_info->phy_id = buffer->PhyNum;
1600 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001601 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001602 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001603 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001604 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1605 device_info->sas_address = le64_to_cpu(sas_address);
1606 device_info->device_info =
1607 le32_to_cpu(buffer->DeviceInfo);
1608
1609 out_free_consistent:
1610 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1611 buffer, dma_handle);
1612 out:
1613 return error;
1614}
1615
1616static int
1617mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1618 u32 form, u32 form_specific)
1619{
1620 ConfigExtendedPageHeader_t hdr;
1621 CONFIGPARMS cfg;
1622 SasExpanderPage0_t *buffer;
1623 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001624 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001625
1626 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1627 hdr.ExtPageLength = 0;
1628 hdr.PageNumber = 0;
1629 hdr.Reserved1 = 0;
1630 hdr.Reserved2 = 0;
1631 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1632 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1633
1634 cfg.cfghdr.ehdr = &hdr;
1635 cfg.physAddr = -1;
1636 cfg.pageAddr = form + form_specific;
1637 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1638 cfg.dir = 0; /* read */
1639 cfg.timeout = 10;
1640
Moore, Ericdb9c9172006-03-14 09:14:18 -07001641 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001642 error = mpt_config(ioc, &cfg);
1643 if (error)
1644 goto out;
1645
1646 if (!hdr.ExtPageLength) {
1647 error = -ENXIO;
1648 goto out;
1649 }
1650
1651 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1652 &dma_handle);
1653 if (!buffer) {
1654 error = -ENOMEM;
1655 goto out;
1656 }
1657
1658 cfg.physAddr = dma_handle;
1659 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1660
1661 error = mpt_config(ioc, &cfg);
1662 if (error)
1663 goto out_free_consistent;
1664
1665 /* save config data */
1666 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001667 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001668 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001669 if (!port_info->phy_info) {
1670 error = -ENOMEM;
1671 goto out_free_consistent;
1672 }
1673
Eric Moore2ecce492007-01-29 09:47:08 -07001674 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001675 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001676 port_info->phy_info[i].handle =
1677 le16_to_cpu(buffer->DevHandle);
1678 }
Eric Moore547f9a22006-06-27 14:42:12 -06001679
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001680 out_free_consistent:
1681 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1682 buffer, dma_handle);
1683 out:
1684 return error;
1685}
1686
1687static int
1688mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1689 u32 form, u32 form_specific)
1690{
1691 ConfigExtendedPageHeader_t hdr;
1692 CONFIGPARMS cfg;
1693 SasExpanderPage1_t *buffer;
1694 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001695 int error=0;
1696
1697 if (ioc->sas_discovery_runtime &&
1698 mptsas_is_end_device(&phy_info->attached))
1699 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001700
1701 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1702 hdr.ExtPageLength = 0;
1703 hdr.PageNumber = 1;
1704 hdr.Reserved1 = 0;
1705 hdr.Reserved2 = 0;
1706 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1707 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1708
1709 cfg.cfghdr.ehdr = &hdr;
1710 cfg.physAddr = -1;
1711 cfg.pageAddr = form + form_specific;
1712 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1713 cfg.dir = 0; /* read */
1714 cfg.timeout = 10;
1715
1716 error = mpt_config(ioc, &cfg);
1717 if (error)
1718 goto out;
1719
1720 if (!hdr.ExtPageLength) {
1721 error = -ENXIO;
1722 goto out;
1723 }
1724
1725 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1726 &dma_handle);
1727 if (!buffer) {
1728 error = -ENOMEM;
1729 goto out;
1730 }
1731
1732 cfg.physAddr = dma_handle;
1733 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1734
1735 error = mpt_config(ioc, &cfg);
1736 if (error)
1737 goto out_free_consistent;
1738
1739
1740 mptsas_print_expander_pg1(buffer);
1741
1742 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001743 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001744 phy_info->port_id = buffer->PhysicalPort;
1745 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1746 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1747 phy_info->hw_link_rate = buffer->HwLinkRate;
1748 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1749 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1750
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001751 out_free_consistent:
1752 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1753 buffer, dma_handle);
1754 out:
1755 return error;
1756}
1757
1758static void
1759mptsas_parse_device_info(struct sas_identify *identify,
1760 struct mptsas_devinfo *device_info)
1761{
1762 u16 protocols;
1763
1764 identify->sas_address = device_info->sas_address;
1765 identify->phy_identifier = device_info->phy_id;
1766
1767 /*
1768 * Fill in Phy Initiator Port Protocol.
1769 * Bits 6:3, more than one bit can be set, fall through cases.
1770 */
1771 protocols = device_info->device_info & 0x78;
1772 identify->initiator_port_protocols = 0;
1773 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1774 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1775 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1776 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1777 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1778 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1779 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1780 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1781
1782 /*
1783 * Fill in Phy Target Port Protocol.
1784 * Bits 10:7, more than one bit can be set, fall through cases.
1785 */
1786 protocols = device_info->device_info & 0x780;
1787 identify->target_port_protocols = 0;
1788 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1789 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1790 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1791 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1792 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1793 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1794 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1795 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1796
1797 /*
1798 * Fill in Attached device type.
1799 */
1800 switch (device_info->device_info &
1801 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1802 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1803 identify->device_type = SAS_PHY_UNUSED;
1804 break;
1805 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1806 identify->device_type = SAS_END_DEVICE;
1807 break;
1808 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1809 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1810 break;
1811 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1812 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1813 break;
1814 }
1815}
1816
1817static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001818 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001819{
Moore, Erice6b2d762006-03-14 09:14:24 -07001820 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001821 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001822 struct sas_port *port;
1823 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moore547f9a22006-06-27 14:42:12 -06001825 if (!dev) {
1826 error = -ENODEV;
1827 goto out;
1828 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001829
1830 if (!phy_info->phy) {
1831 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001832 if (!phy) {
1833 error = -ENOMEM;
1834 goto out;
1835 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001836 } else
1837 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001839 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840
1841 /*
1842 * Set Negotiated link rate.
1843 */
1844 switch (phy_info->negotiated_link_rate) {
1845 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001846 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001847 break;
1848 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001849 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001850 break;
1851 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001852 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853 break;
1854 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001855 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001856 break;
1857 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1858 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1859 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001860 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001861 break;
1862 }
1863
1864 /*
1865 * Set Max hardware link rate.
1866 */
1867 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1868 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001869 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001870 break;
1871 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001872 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001873 break;
1874 default:
1875 break;
1876 }
1877
1878 /*
1879 * Set Max programmed link rate.
1880 */
1881 switch (phy_info->programmed_link_rate &
1882 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1883 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001884 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 break;
1886 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001887 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 break;
1889 default:
1890 break;
1891 }
1892
1893 /*
1894 * Set Min hardware link rate.
1895 */
1896 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1897 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001898 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001899 break;
1900 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001901 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001902 break;
1903 default:
1904 break;
1905 }
1906
1907 /*
1908 * Set Min programmed link rate.
1909 */
1910 switch (phy_info->programmed_link_rate &
1911 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1912 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001913 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001914 break;
1915 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001916 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001917 break;
1918 default:
1919 break;
1920 }
1921
Moore, Erice6b2d762006-03-14 09:14:24 -07001922 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001923
Moore, Erice6b2d762006-03-14 09:14:24 -07001924 error = sas_phy_add(phy);
1925 if (error) {
1926 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001927 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001928 }
1929 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001930 }
1931
Eric Moore547f9a22006-06-27 14:42:12 -06001932 if (!phy_info->attached.handle ||
1933 !phy_info->port_details)
1934 goto out;
1935
1936 port = mptsas_get_port(phy_info);
1937 ioc = phy_to_ioc(phy_info->phy);
1938
1939 if (phy_info->sas_port_add_phy) {
1940
1941 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001942 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001943 if (!port) {
1944 error = -ENOMEM;
1945 goto out;
1946 }
1947 error = sas_port_add(port);
1948 if (error) {
1949 dfailprintk((MYIOC_s_ERR_FMT
1950 "%s: exit at line=%d\n", ioc->name,
1951 __FUNCTION__, __LINE__));
1952 goto out;
1953 }
1954 mptsas_set_port(phy_info, port);
Eric Mooredc22f162006-07-06 11:23:14 -06001955 dsaswideprintk((KERN_DEBUG
1956 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1957 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001958 }
1959 dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
1960 phy_info->phy_id));
1961 sas_port_add_phy(port, phy_info->phy);
1962 phy_info->sas_port_add_phy = 0;
1963 }
1964
1965 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001966
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001967 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001968 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001969 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001970
James Bottomley2686de22006-06-30 12:54:02 -05001971 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001972 /*
1973 * Let the hotplug_work thread handle processing
1974 * the adding/removing of devices that occur
1975 * after start of day.
1976 */
1977 if (ioc->sas_discovery_runtime &&
1978 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001979 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001980
James Bottomleyf013db32006-03-18 14:54:36 -06001981 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001982 if (scsi_is_host_device(parent)) {
1983 struct mptsas_portinfo *port_info;
1984 int i;
1985
1986 mutex_lock(&ioc->sas_topology_mutex);
1987 port_info = mptsas_find_portinfo_by_handle(ioc,
1988 ioc->handle);
1989 mutex_unlock(&ioc->sas_topology_mutex);
1990
1991 for (i = 0; i < port_info->num_phys; i++)
1992 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001993 identify.sas_address) {
1994 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001995 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001996 }
James Bottomley2686de22006-06-30 12:54:02 -05001997
1998 } else if (scsi_is_sas_rphy(parent)) {
1999 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2000 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002001 parent_rphy->identify.sas_address) {
2002 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002003 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002004 }
James Bottomley2686de22006-06-30 12:54:02 -05002005 }
2006
James Bottomleyf013db32006-03-18 14:54:36 -06002007 switch (identify.device_type) {
2008 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002009 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002010 break;
2011 case SAS_EDGE_EXPANDER_DEVICE:
2012 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002013 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002014 break;
2015 default:
2016 rphy = NULL;
2017 break;
2018 }
Eric Moore547f9a22006-06-27 14:42:12 -06002019 if (!rphy) {
2020 dfailprintk((MYIOC_s_ERR_FMT
2021 "%s: exit at line=%d\n", ioc->name,
2022 __FUNCTION__, __LINE__));
2023 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002024 }
2025
Eric Moore547f9a22006-06-27 14:42:12 -06002026 rphy->identify = identify;
2027 error = sas_rphy_add(rphy);
2028 if (error) {
2029 dfailprintk((MYIOC_s_ERR_FMT
2030 "%s: exit at line=%d\n", ioc->name,
2031 __FUNCTION__, __LINE__));
2032 sas_rphy_free(rphy);
2033 goto out;
2034 }
2035 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002036 }
2037
Eric Moore547f9a22006-06-27 14:42:12 -06002038 out:
2039 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002040}
2041
2042static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002043mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002044{
Moore, Erice6b2d762006-03-14 09:14:24 -07002045 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002046 int error = -ENOMEM, i;
2047
Moore, Erice6b2d762006-03-14 09:14:24 -07002048 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2049 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002050 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002051
Moore, Erice6b2d762006-03-14 09:14:24 -07002052 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002053 if (error)
2054 goto out_free_port_info;
2055
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302056 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002057 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002058 ioc->handle = hba->phy_info[0].handle;
2059 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002060 if (!port_info) {
2061 port_info = hba;
2062 list_add_tail(&port_info->list, &ioc->sas_topology);
2063 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002064 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002065 port_info->phy_info[i].negotiated_link_rate =
2066 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002067 port_info->phy_info[i].handle =
2068 hba->phy_info[i].handle;
2069 port_info->phy_info[i].port_id =
2070 hba->phy_info[i].port_id;
2071 }
Eric Moore547f9a22006-06-27 14:42:12 -06002072 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002073 kfree(hba);
2074 hba = NULL;
2075 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002076 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002077 for (i = 0; i < port_info->num_phys; i++) {
2078 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2079 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2080 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2081
2082 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002083 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2084 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2085 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002086 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002087 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002088 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002089 mptsas_sas_device_pg0(ioc,
2090 &port_info->phy_info[i].attached,
2091 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2092 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2093 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002094 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002095
Eric Moore547f9a22006-06-27 14:42:12 -06002096 mptsas_setup_wide_ports(ioc, port_info);
2097
2098 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002099 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002100 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002101
2102 return 0;
2103
2104 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002105 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002106 out:
2107 return error;
2108}
2109
2110static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002111mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002112{
Moore, Erice6b2d762006-03-14 09:14:24 -07002113 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002114 struct device *parent;
2115 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002116 int error = -ENOMEM, i, j;
2117
Moore, Erice6b2d762006-03-14 09:14:24 -07002118 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2119 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002120 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002121
Moore, Erice6b2d762006-03-14 09:14:24 -07002122 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002123 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2124 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002125 if (error)
2126 goto out_free_port_info;
2127
Eric Moore2ecce492007-01-29 09:47:08 -07002128 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002129
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002130 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002131 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2132 if (!port_info) {
2133 port_info = ex;
2134 list_add_tail(&port_info->list, &ioc->sas_topology);
2135 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002136 for (i = 0; i < ex->num_phys; i++) {
2137 port_info->phy_info[i].handle =
2138 ex->phy_info[i].handle;
2139 port_info->phy_info[i].port_id =
2140 ex->phy_info[i].port_id;
2141 }
Eric Moore547f9a22006-06-27 14:42:12 -06002142 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002143 kfree(ex);
2144 ex = NULL;
2145 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002146 mutex_unlock(&ioc->sas_topology_mutex);
2147
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002148 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002149 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2150 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2151 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2152
2153 if (port_info->phy_info[i].identify.handle) {
2154 mptsas_sas_device_pg0(ioc,
2155 &port_info->phy_info[i].identify,
2156 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2157 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2158 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002159 port_info->phy_info[i].identify.phy_id =
2160 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002161 }
2162
2163 if (port_info->phy_info[i].attached.handle) {
2164 mptsas_sas_device_pg0(ioc,
2165 &port_info->phy_info[i].attached,
2166 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2167 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2168 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002169 port_info->phy_info[i].attached.phy_id =
2170 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002171 }
Eric Moore547f9a22006-06-27 14:42:12 -06002172 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002173
Eric Moore547f9a22006-06-27 14:42:12 -06002174 parent = &ioc->sh->shost_gendev;
2175 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002176 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002177 list_for_each_entry(p, &ioc->sas_topology, list) {
2178 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002179 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002180 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002181 continue;
2182 rphy = mptsas_get_rphy(&p->phy_info[j]);
2183 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002184 }
2185 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002186 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002187 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002188
Eric Moore547f9a22006-06-27 14:42:12 -06002189 mptsas_setup_wide_ports(ioc, port_info);
2190
2191 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002192 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002193 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002194
2195 return 0;
2196
2197 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002198 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002199 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002200 kfree(ex);
2201 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002202 out:
2203 return error;
2204}
2205
Moore, Erice6b2d762006-03-14 09:14:24 -07002206/*
2207 * mptsas_delete_expander_phys
2208 *
2209 *
2210 * This will traverse topology, and remove expanders
2211 * that are no longer present
2212 */
2213static void
2214mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2215{
2216 struct mptsas_portinfo buffer;
2217 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002218 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002219 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002220 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002221 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002222
2223 mutex_lock(&ioc->sas_topology_mutex);
2224 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2225
2226 if (port_info->phy_info &&
2227 (!(port_info->phy_info[0].identify.device_info &
2228 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2229 continue;
2230
2231 if (mptsas_sas_expander_pg0(ioc, &buffer,
2232 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002233 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2234 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002235
2236 /*
2237 * Obtain the port_info instance to the parent port
2238 */
2239 parent = mptsas_find_portinfo_by_handle(ioc,
2240 port_info->phy_info[0].identify.handle_parent);
2241
2242 if (!parent)
2243 goto next_port;
2244
Eric Moore547f9a22006-06-27 14:42:12 -06002245 expander_sas_address =
2246 port_info->phy_info[0].identify.sas_address;
2247
Moore, Erice6b2d762006-03-14 09:14:24 -07002248 /*
2249 * Delete rphys in the parent that point
2250 * to this expander. The transport layer will
2251 * cleanup all the children.
2252 */
Eric Moore547f9a22006-06-27 14:42:12 -06002253 phy_info = parent->phy_info;
2254 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2255 port = mptsas_get_port(phy_info);
2256 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002257 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002258 if (phy_info->attached.sas_address !=
2259 expander_sas_address)
2260 continue;
2261#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002262 dev_printk(KERN_DEBUG, &port->dev,
2263 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002264#endif
2265 sas_port_delete(port);
2266 mptsas_port_delete(phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002267 }
2268 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002269
2270 phy_info = port_info->phy_info;
2271 for (i = 0; i < port_info->num_phys; i++, phy_info++)
2272 mptsas_port_delete(phy_info->port_details);
2273
Moore, Erice6b2d762006-03-14 09:14:24 -07002274 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002275 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002276 kfree(port_info);
2277 }
2278 /*
2279 * Free this memory allocated from inside
2280 * mptsas_sas_expander_pg0
2281 */
Eric Moore547f9a22006-06-27 14:42:12 -06002282 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002283 }
2284 mutex_unlock(&ioc->sas_topology_mutex);
2285}
2286
2287/*
2288 * Start of day discovery
2289 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002290static void
2291mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2292{
2293 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002294 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002295
Moore, Erice6b2d762006-03-14 09:14:24 -07002296 mutex_lock(&ioc->sas_discovery_mutex);
2297 mptsas_probe_hba_phys(ioc);
2298 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002299 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002300 /*
2301 Reporting RAID volumes.
2302 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002303 if (!ioc->ir_firmware)
2304 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002305 if (!ioc->raid_data.pIocPg2)
2306 goto out;
2307 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2308 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002309 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002310 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002311 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2312 }
2313 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002314 mutex_unlock(&ioc->sas_discovery_mutex);
2315}
2316
2317/*
2318 * Work queue thread to handle Runtime discovery
2319 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002320 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002321 */
2322static void
Eric Moore547f9a22006-06-27 14:42:12 -06002323__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002324{
Moore, Erice6b2d762006-03-14 09:14:24 -07002325 u32 handle = 0xFFFF;
2326
Moore, Erice6b2d762006-03-14 09:14:24 -07002327 ioc->sas_discovery_runtime=1;
2328 mptsas_delete_expander_phys(ioc);
2329 mptsas_probe_hba_phys(ioc);
2330 while (!mptsas_probe_expander_phys(ioc, &handle))
2331 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002332 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002333}
2334
2335/*
2336 * Work queue thread to handle Runtime discovery
2337 * Mere purpose is the hot add/delete of expanders
2338 *(Mutex LOCKED)
2339 */
2340static void
David Howellsc4028952006-11-22 14:57:56 +00002341mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002342{
David Howellsc4028952006-11-22 14:57:56 +00002343 struct mptsas_discovery_event *ev =
2344 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002345 MPT_ADAPTER *ioc = ev->ioc;
2346
2347 mutex_lock(&ioc->sas_discovery_mutex);
2348 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002349 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002350 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002351}
2352
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002353static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002354mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002355{
2356 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002357 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002358 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002359
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002360 mutex_lock(&ioc->sas_topology_mutex);
2361 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2362 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002363 if (!mptsas_is_end_device(
2364 &port_info->phy_info[i].attached))
2365 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002366 if (port_info->phy_info[i].attached.sas_address
2367 != sas_address)
2368 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002369 phy_info = &port_info->phy_info[i];
2370 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002371 }
2372 }
2373 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002374 return phy_info;
2375}
2376
2377static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002378mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002379{
2380 struct mptsas_portinfo *port_info;
2381 struct mptsas_phyinfo *phy_info = NULL;
2382 int i;
2383
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002384 mutex_lock(&ioc->sas_topology_mutex);
2385 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002386 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002387 if (!mptsas_is_end_device(
2388 &port_info->phy_info[i].attached))
2389 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002390 if (port_info->phy_info[i].attached.id != id)
2391 continue;
2392 if (port_info->phy_info[i].attached.channel != channel)
2393 continue;
2394 phy_info = &port_info->phy_info[i];
2395 break;
2396 }
2397 }
2398 mutex_unlock(&ioc->sas_topology_mutex);
2399 return phy_info;
2400}
2401
2402static struct mptsas_phyinfo *
2403mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2404{
2405 struct mptsas_portinfo *port_info;
2406 struct mptsas_phyinfo *phy_info = NULL;
2407 int i;
2408
2409 mutex_lock(&ioc->sas_topology_mutex);
2410 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2411 for (i = 0; i < port_info->num_phys; i++) {
2412 if (!mptsas_is_end_device(
2413 &port_info->phy_info[i].attached))
2414 continue;
2415 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2416 continue;
2417 if (port_info->phy_info[i].attached.phys_disk_num != id)
2418 continue;
2419 if (port_info->phy_info[i].attached.channel != channel)
2420 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002421 phy_info = &port_info->phy_info[i];
2422 break;
2423 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002424 }
2425 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002426 return phy_info;
2427}
2428
Moore, Eric4b766472006-03-14 09:14:12 -07002429/*
2430 * Work queue thread to clear the persitency table
2431 */
2432static void
David Howellsc4028952006-11-22 14:57:56 +00002433mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002434{
David Howellsc4028952006-11-22 14:57:56 +00002435 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002436
2437 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2438}
2439
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002440static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002441mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2442{
Eric Mooref99be432007-01-04 20:46:54 -07002443 int rc;
2444
Moore, Ericf44e5462006-03-14 09:14:21 -07002445 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002446 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002447}
2448
2449static void
2450mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2451{
2452 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2453 mptsas_reprobe_lun);
2454}
2455
Eric Mooreb506ade2007-01-29 09:45:37 -07002456static void
2457mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2458{
2459 CONFIGPARMS cfg;
2460 ConfigPageHeader_t hdr;
2461 dma_addr_t dma_handle;
2462 pRaidVolumePage0_t buffer = NULL;
2463 RaidPhysDiskPage0_t phys_disk;
2464 int i;
2465 struct mptsas_hotplug_event *ev;
2466
2467 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2468 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2469 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2470 cfg.pageAddr = (channel << 8) + id;
2471 cfg.cfghdr.hdr = &hdr;
2472 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2473
2474 if (mpt_config(ioc, &cfg) != 0)
2475 goto out;
2476
2477 if (!hdr.PageLength)
2478 goto out;
2479
2480 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2481 &dma_handle);
2482
2483 if (!buffer)
2484 goto out;
2485
2486 cfg.physAddr = dma_handle;
2487 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2488
2489 if (mpt_config(ioc, &cfg) != 0)
2490 goto out;
2491
2492 if (!(buffer->VolumeStatus.Flags &
2493 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2494 goto out;
2495
2496 if (!buffer->NumPhysDisks)
2497 goto out;
2498
2499 for (i = 0; i < buffer->NumPhysDisks; i++) {
2500
2501 if (mpt_raid_phys_disk_pg0(ioc,
2502 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2503 continue;
2504
2505 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2506 if (!ev) {
2507 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2508 goto out;
2509 }
2510
2511 INIT_WORK(&ev->work, mptsas_hotplug_work);
2512 ev->ioc = ioc;
2513 ev->id = phys_disk.PhysDiskID;
2514 ev->channel = phys_disk.PhysDiskBus;
2515 ev->phys_disk_num_valid = 1;
2516 ev->phys_disk_num = phys_disk.PhysDiskNum;
2517 ev->event_type = MPTSAS_ADD_DEVICE;
2518 schedule_work(&ev->work);
2519 }
2520
2521 out:
2522 if (buffer)
2523 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2524 dma_handle);
2525}
Moore, Erice6b2d762006-03-14 09:14:24 -07002526/*
2527 * Work queue thread to handle SAS hotplug events
2528 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002529static void
David Howellsc4028952006-11-22 14:57:56 +00002530mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002531{
David Howellsc4028952006-11-22 14:57:56 +00002532 struct mptsas_hotplug_event *ev =
2533 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002534
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002535 MPT_ADAPTER *ioc = ev->ioc;
2536 struct mptsas_phyinfo *phy_info;
2537 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002538 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002539 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002540 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002541 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002542 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002543 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002544 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002545 VirtDevice *vdevice;
2546
Moore, Erice6b2d762006-03-14 09:14:24 -07002547 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002548 switch (ev->event_type) {
2549 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002550
Eric Mooreb506ade2007-01-29 09:45:37 -07002551 phy_info = NULL;
2552 if (ev->phys_disk_num_valid) {
2553 if (ev->hidden_raid_component){
2554 if (mptsas_sas_device_pg0(ioc, &sas_device,
2555 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2556 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2557 (ev->channel << 8) + ev->id)) {
2558 dfailprintk((MYIOC_s_ERR_FMT
2559 "%s: exit at line=%d\n", ioc->name,
2560 __FUNCTION__, __LINE__));
2561 break;
2562 }
2563 phy_info = mptsas_find_phyinfo_by_sas_address(
2564 ioc, sas_device.sas_address);
2565 }else
2566 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2567 ioc, ev->channel, ev->phys_disk_num);
2568 }
2569
2570 if (!phy_info)
2571 phy_info = mptsas_find_phyinfo_by_target(ioc,
2572 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002573
Moore, Ericf44e5462006-03-14 09:14:21 -07002574 /*
2575 * Sanity checks, for non-existing phys and remote rphys.
2576 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002577 if (!phy_info){
2578 dfailprintk((MYIOC_s_ERR_FMT
2579 "%s: exit at line=%d\n", ioc->name,
2580 __FUNCTION__, __LINE__));
2581 break;
2582 }
2583 if (!phy_info->port_details) {
Eric Moore547f9a22006-06-27 14:42:12 -06002584 dfailprintk((MYIOC_s_ERR_FMT
2585 "%s: exit at line=%d\n", ioc->name,
2586 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002587 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002588 }
2589 rphy = mptsas_get_rphy(phy_info);
2590 if (!rphy) {
2591 dfailprintk((MYIOC_s_ERR_FMT
2592 "%s: exit at line=%d\n", ioc->name,
2593 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002594 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002595 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002596
Eric Moore547f9a22006-06-27 14:42:12 -06002597 port = mptsas_get_port(phy_info);
2598 if (!port) {
2599 dfailprintk((MYIOC_s_ERR_FMT
2600 "%s: exit at line=%d\n", ioc->name,
2601 __FUNCTION__, __LINE__));
2602 break;
2603 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002604
Eric Moore547f9a22006-06-27 14:42:12 -06002605 starget = mptsas_get_starget(phy_info);
2606 if (starget) {
2607 vtarget = starget->hostdata;
2608
2609 if (!vtarget) {
2610 dfailprintk((MYIOC_s_ERR_FMT
2611 "%s: exit at line=%d\n", ioc->name,
2612 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002613 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002614 }
2615
Moore, Ericf44e5462006-03-14 09:14:21 -07002616 /*
2617 * Handling RAID components
2618 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002619 if (ev->phys_disk_num_valid &&
2620 ev->hidden_raid_component) {
2621 printk(MYIOC_s_INFO_FMT
2622 "RAID Hidding: channel=%d, id=%d, "
2623 "physdsk %d \n", ioc->name, ev->channel,
2624 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002625 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002626 vtarget->tflags |=
2627 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002628 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002629 phy_info->attached.phys_disk_num =
2630 ev->phys_disk_num;
2631 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002632 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002633 }
2634
Eric Mooreb506ade2007-01-29 09:45:37 -07002635 if (phy_info->attached.device_info &
2636 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002637 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002638 if (phy_info->attached.device_info &
2639 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002640 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002641 if (phy_info->attached.device_info &
2642 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002643 ds = "sata";
2644
2645 printk(MYIOC_s_INFO_FMT
2646 "removing %s device, channel %d, id %d, phy %d\n",
2647 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore547f9a22006-06-27 14:42:12 -06002648#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002649 dev_printk(KERN_DEBUG, &port->dev,
2650 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002651#endif
2652 sas_port_delete(port);
2653 mptsas_port_delete(phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002654 break;
2655 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002656
Moore, Ericbd23e942006-04-17 12:43:04 -06002657 if (ev->phys_disk_num_valid)
2658 mpt_findImVolumes(ioc);
2659
Moore, Ericc73787ee2006-01-26 16:20:06 -07002660 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002661 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002662 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002663 if (mptsas_sas_device_pg0(ioc, &sas_device,
2664 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002665 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2666 (ev->channel << 8) + ev->id)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002667 dfailprintk((MYIOC_s_ERR_FMT
2668 "%s: exit at line=%d\n", ioc->name,
2669 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002670 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002671 }
2672
Eric Moore547f9a22006-06-27 14:42:12 -06002673 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002674
Eric Moore547f9a22006-06-27 14:42:12 -06002675 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2676 sas_device.sas_address);
2677
2678 if (!phy_info || !phy_info->port_details) {
2679 dfailprintk((MYIOC_s_ERR_FMT
2680 "%s: exit at line=%d\n", ioc->name,
2681 __FUNCTION__, __LINE__));
2682 break;
2683 }
2684
2685 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002686 if (starget && (!ev->hidden_raid_component)){
2687
Eric Moore547f9a22006-06-27 14:42:12 -06002688 vtarget = starget->hostdata;
2689
2690 if (!vtarget) {
2691 dfailprintk((MYIOC_s_ERR_FMT
2692 "%s: exit at line=%d\n", ioc->name,
2693 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002694 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002695 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002696 /*
2697 * Handling RAID components
2698 */
2699 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002700 printk(MYIOC_s_INFO_FMT
2701 "RAID Exposing: channel=%d, id=%d, "
2702 "physdsk %d \n", ioc->name, ev->channel,
2703 ev->id, ev->phys_disk_num);
2704 vtarget->tflags &=
2705 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002706 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002707 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002708 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002709 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002710 break;
2711 }
2712
Eric Moore547f9a22006-06-27 14:42:12 -06002713 if (mptsas_get_rphy(phy_info)) {
2714 dfailprintk((MYIOC_s_ERR_FMT
2715 "%s: exit at line=%d\n", ioc->name,
2716 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002717 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002718 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002719 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002720
Eric Moore547f9a22006-06-27 14:42:12 -06002721 port = mptsas_get_port(phy_info);
2722 if (!port) {
2723 dfailprintk((MYIOC_s_ERR_FMT
2724 "%s: exit at line=%d\n", ioc->name,
2725 __FUNCTION__, __LINE__));
2726 break;
2727 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002728 memcpy(&phy_info->attached, &sas_device,
2729 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002730
Eric Mooreb506ade2007-01-29 09:45:37 -07002731 if (phy_info->attached.device_info &
2732 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002733 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002734 if (phy_info->attached.device_info &
2735 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002736 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002737 if (phy_info->attached.device_info &
2738 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002739 ds = "sata";
2740
2741 printk(MYIOC_s_INFO_FMT
2742 "attaching %s device, channel %d, id %d, phy %d\n",
2743 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2744
James Bottomleyf013db32006-03-18 14:54:36 -06002745 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002746 rphy = sas_end_device_alloc(port);
2747 if (!rphy) {
2748 dfailprintk((MYIOC_s_ERR_FMT
2749 "%s: exit at line=%d\n", ioc->name,
2750 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002751 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002752 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002753
James Bottomleyf013db32006-03-18 14:54:36 -06002754 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002755 if (sas_rphy_add(rphy)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002756 dfailprintk((MYIOC_s_ERR_FMT
2757 "%s: exit at line=%d\n", ioc->name,
2758 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002759 sas_rphy_free(rphy);
2760 break;
2761 }
Eric Moore547f9a22006-06-27 14:42:12 -06002762 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002763 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002764 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002765 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2766 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002767 if (sdev) {
2768 scsi_device_put(sdev);
2769 break;
2770 }
2771 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002772 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002773 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2774 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002775 mpt_findImVolumes(ioc);
2776 break;
2777 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002778 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002779 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002780 if (!sdev)
2781 break;
2782 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002783 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002784 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002785 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002786 scsi_remove_device(sdev);
2787 scsi_device_put(sdev);
2788 mpt_findImVolumes(ioc);
2789 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002790 case MPTSAS_ADD_INACTIVE_VOLUME:
2791 mptsas_adding_inactive_raid_components(ioc,
2792 ev->channel, ev->id);
2793 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002794 case MPTSAS_IGNORE_EVENT:
2795 default:
2796 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002797 }
2798
Moore, Erice6b2d762006-03-14 09:14:24 -07002799 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002800 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002801}
2802
2803static void
Eric Moore547f9a22006-06-27 14:42:12 -06002804mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002805 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2806{
2807 struct mptsas_hotplug_event *ev;
2808 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2809 __le64 sas_address;
2810
2811 if ((device_info &
2812 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2813 MPI_SAS_DEVICE_INFO_STP_TARGET |
2814 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2815 return;
2816
Moore, Eric4b766472006-03-14 09:14:12 -07002817 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002818 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002819
2820 mptsas_target_reset_queue(ioc, sas_event_data);
2821 break;
2822
2823 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002824 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002825 if (!ev) {
2826 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2827 break;
2828 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002829
David Howellsc4028952006-11-22 14:57:56 +00002830 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002831 ev->ioc = ioc;
2832 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2833 ev->parent_handle =
2834 le16_to_cpu(sas_event_data->ParentDevHandle);
2835 ev->channel = sas_event_data->Bus;
2836 ev->id = sas_event_data->TargetID;
2837 ev->phy_id = sas_event_data->PhyNum;
2838 memcpy(&sas_address, &sas_event_data->SASAddress,
2839 sizeof(__le64));
2840 ev->sas_address = le64_to_cpu(sas_address);
2841 ev->device_info = device_info;
2842
2843 if (sas_event_data->ReasonCode &
2844 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2845 ev->event_type = MPTSAS_ADD_DEVICE;
2846 else
2847 ev->event_type = MPTSAS_DEL_DEVICE;
2848 schedule_work(&ev->work);
2849 break;
2850 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2851 /*
2852 * Persistent table is full.
2853 */
Eric Moore547f9a22006-06-27 14:42:12 -06002854 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002855 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002856 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002857 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002858 /*
2859 * TODO, handle other events
2860 */
Moore, Eric4b766472006-03-14 09:14:12 -07002861 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002862 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002863 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002864 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2865 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2866 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2867 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002868 default:
2869 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002870 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002871}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002872static void
Eric Moore547f9a22006-06-27 14:42:12 -06002873mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002874 EVENT_DATA_RAID *raid_event_data)
2875{
2876 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002877 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2878 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002879
2880 if (ioc->bus_type != SAS)
2881 return;
2882
Eric Moore547f9a22006-06-27 14:42:12 -06002883 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002884 if (!ev) {
2885 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2886 return;
2887 }
2888
David Howellsc4028952006-11-22 14:57:56 +00002889 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002890 ev->ioc = ioc;
2891 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002892 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002893 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002894
2895 switch (raid_event_data->ReasonCode) {
2896 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002897 ev->phys_disk_num_valid = 1;
2898 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002899 ev->event_type = MPTSAS_ADD_DEVICE;
2900 break;
2901 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002902 ev->phys_disk_num_valid = 1;
2903 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002904 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002905 ev->event_type = MPTSAS_DEL_DEVICE;
2906 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002907 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2908 switch (state) {
2909 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002910 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002911 ev->phys_disk_num_valid = 1;
2912 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002913 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002914 ev->event_type = MPTSAS_ADD_DEVICE;
2915 break;
2916 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002917 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2918 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2919 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002920 ev->phys_disk_num_valid = 1;
2921 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002922 ev->event_type = MPTSAS_DEL_DEVICE;
2923 break;
2924 default:
2925 break;
2926 }
2927 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002928 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2929 ev->event_type = MPTSAS_DEL_RAID;
2930 break;
2931 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2932 ev->event_type = MPTSAS_ADD_RAID;
2933 break;
2934 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002935 switch (state) {
2936 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2937 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2938 ev->event_type = MPTSAS_DEL_RAID;
2939 break;
2940 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2941 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2942 ev->event_type = MPTSAS_ADD_RAID;
2943 break;
2944 default:
2945 break;
2946 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002947 break;
2948 default:
2949 break;
2950 }
2951 schedule_work(&ev->work);
2952}
2953
Moore, Erice6b2d762006-03-14 09:14:24 -07002954static void
Eric Moore547f9a22006-06-27 14:42:12 -06002955mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002956 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2957{
2958 struct mptsas_discovery_event *ev;
2959
2960 /*
2961 * DiscoveryStatus
2962 *
2963 * This flag will be non-zero when firmware
2964 * kicks off discovery, and return to zero
2965 * once its completed.
2966 */
2967 if (discovery_data->DiscoveryStatus)
2968 return;
2969
Eric Moore547f9a22006-06-27 14:42:12 -06002970 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002971 if (!ev)
2972 return;
David Howellsc4028952006-11-22 14:57:56 +00002973 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002974 ev->ioc = ioc;
2975 schedule_work(&ev->work);
2976};
2977
Eric Mooreb506ade2007-01-29 09:45:37 -07002978/*
2979 * mptsas_send_ir2_event - handle exposing hidden disk when
2980 * an inactive raid volume is added
2981 *
2982 * @ioc: Pointer to MPT_ADAPTER structure
2983 * @ir2_data
2984 *
2985 */
2986static void
2987mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2988{
2989 struct mptsas_hotplug_event *ev;
2990
2991 if (ir2_data->ReasonCode !=
2992 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2993 return;
2994
2995 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2996 if (!ev)
2997 return;
2998
2999 INIT_WORK(&ev->work, mptsas_hotplug_work);
3000 ev->ioc = ioc;
3001 ev->id = ir2_data->TargetID;
3002 ev->channel = ir2_data->Bus;
3003 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3004
3005 schedule_work(&ev->work);
3006};
Moore, Erice6b2d762006-03-14 09:14:24 -07003007
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003008static int
3009mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3010{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003011 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003012 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3013
3014 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003015 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003016
Moore, Erice6b2d762006-03-14 09:14:24 -07003017 /*
3018 * sas_discovery_ignore_events
3019 *
3020 * This flag is to prevent anymore processing of
3021 * sas events once mptsas_remove function is called.
3022 */
3023 if (ioc->sas_discovery_ignore_events) {
3024 rc = mptscsih_event_process(ioc, reply);
3025 goto out;
3026 }
3027
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003028 switch (event) {
3029 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003030 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003031 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003032 break;
3033 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003034 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003035 (EVENT_DATA_RAID *)reply->Data);
3036 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003037 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003038 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003039 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003040 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003041 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003042 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003043 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003044 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3045 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003046 case MPI_EVENT_IR2:
3047 mptsas_send_ir2_event(ioc,
3048 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3049 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003050 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003051 rc = mptscsih_event_process(ioc, reply);
3052 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003053 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003054 out:
3055
3056 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003057}
3058
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003059static int
3060mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3061{
3062 struct Scsi_Host *sh;
3063 MPT_SCSI_HOST *hd;
3064 MPT_ADAPTER *ioc;
3065 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003066 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003067 int numSGE = 0;
3068 int scale;
3069 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003070 int error=0;
3071 int r;
3072
3073 r = mpt_attach(pdev,id);
3074 if (r)
3075 return r;
3076
3077 ioc = pci_get_drvdata(pdev);
3078 ioc->DoneCtx = mptsasDoneCtx;
3079 ioc->TaskCtx = mptsasTaskCtx;
3080 ioc->InternalCtx = mptsasInternalCtx;
3081
3082 /* Added sanity check on readiness of the MPT adapter.
3083 */
3084 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3085 printk(MYIOC_s_WARN_FMT
3086 "Skipping because it's not operational!\n",
3087 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003088 error = -ENODEV;
3089 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003090 }
3091
3092 if (!ioc->active) {
3093 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3094 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003095 error = -ENODEV;
3096 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003097 }
3098
3099 /* Sanity check - ensure at least 1 port is INITIATOR capable
3100 */
3101 ioc_cap = 0;
3102 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3103 if (ioc->pfacts[ii].ProtocolFlags &
3104 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3105 ioc_cap++;
3106 }
3107
3108 if (!ioc_cap) {
3109 printk(MYIOC_s_WARN_FMT
3110 "Skipping ioc=%p because SCSI Initiator mode "
3111 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003112 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003113 }
3114
3115 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3116 if (!sh) {
3117 printk(MYIOC_s_WARN_FMT
3118 "Unable to register controller with SCSI subsystem\n",
3119 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003120 error = -1;
3121 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003122 }
3123
3124 spin_lock_irqsave(&ioc->FreeQlock, flags);
3125
3126 /* Attach the SCSI Host to the IOC structure
3127 */
3128 ioc->sh = sh;
3129
3130 sh->io_port = 0;
3131 sh->n_io_port = 0;
3132 sh->irq = 0;
3133
3134 /* set 16 byte cdb's */
3135 sh->max_cmd_len = 16;
3136
Eric Moore793955f2007-01-29 09:42:20 -07003137 sh->max_id = ioc->pfacts[0].PortSCSIID;
3138 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003139
3140 sh->transportt = mptsas_transport_template;
3141
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003142 sh->this_id = ioc->pfacts[0].PortSCSIID;
3143
3144 /* Required entry.
3145 */
3146 sh->unique_id = ioc->id;
3147
3148 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003149 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003150 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003151 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003152 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003153
3154 /* Verify that we won't exceed the maximum
3155 * number of chain buffers
3156 * We can optimize: ZZ = req_sz/sizeof(SGE)
3157 * For 32bit SGE's:
3158 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3159 * + (req_sz - 64)/sizeof(SGE)
3160 * A slightly different algorithm is required for
3161 * 64bit SGEs.
3162 */
3163 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3164 if (sizeof(dma_addr_t) == sizeof(u64)) {
3165 numSGE = (scale - 1) *
3166 (ioc->facts.MaxChainDepth-1) + scale +
3167 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3168 sizeof(u32));
3169 } else {
3170 numSGE = 1 + (scale - 1) *
3171 (ioc->facts.MaxChainDepth-1) + scale +
3172 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3173 sizeof(u32));
3174 }
3175
3176 if (numSGE < sh->sg_tablesize) {
3177 /* Reset this value */
3178 dprintk((MYIOC_s_INFO_FMT
3179 "Resetting sg_tablesize to %d from %d\n",
3180 ioc->name, numSGE, sh->sg_tablesize));
3181 sh->sg_tablesize = numSGE;
3182 }
3183
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003184 hd = (MPT_SCSI_HOST *) sh->hostdata;
3185 hd->ioc = ioc;
3186
3187 /* SCSI needs scsi_cmnd lookup table!
3188 * (with size equal to req_depth*PtrSz!)
3189 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003190 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3191 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003193 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003194 }
3195
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003196 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
3197 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003198
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003199 /* Clear the TM flags
3200 */
3201 hd->tmPending = 0;
3202 hd->tmState = TM_STATE_NONE;
3203 hd->resetPending = 0;
3204 hd->abortSCpnt = NULL;
3205
3206 /* Clear the pointer used to store
3207 * single-threaded commands, i.e., those
3208 * issued during a bus scan, dv and
3209 * configuration pages.
3210 */
3211 hd->cmdPtr = NULL;
3212
3213 /* Initialize this SCSI Hosts' timers
3214 * To use, set the timer expires field
3215 * and add_timer
3216 */
3217 init_timer(&hd->timer);
3218 hd->timer.data = (unsigned long) hd;
3219 hd->timer.function = mptscsih_timer_expired;
3220
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003221 ioc->sas_data.ptClear = mpt_pt_clear;
3222
Eric Mooredf9e0622007-01-29 09:46:21 -07003223 init_waitqueue_head(&hd->scandv_waitq);
3224 hd->scandv_wait_done = 0;
3225 hd->last_queue_full = 0;
3226 INIT_LIST_HEAD(&hd->target_reset_list);
3227 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3228
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003229 if (ioc->sas_data.ptClear==1) {
3230 mptbase_sas_persist_operation(
3231 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3232 }
3233
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 error = scsi_add_host(sh, &ioc->pcidev->dev);
3235 if (error) {
3236 dprintk((KERN_ERR MYNAM
3237 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003238 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003239 }
3240
3241 mptsas_scan_sas_topology(ioc);
3242
3243 return 0;
3244
Eric Moore547f9a22006-06-27 14:42:12 -06003245 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003246
3247 mptscsih_remove(pdev);
3248 return error;
3249}
3250
3251static void __devexit mptsas_remove(struct pci_dev *pdev)
3252{
3253 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3254 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003255 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003256
Eric Mooreb506ade2007-01-29 09:45:37 -07003257 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003258 sas_remove_host(ioc->sh);
3259
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003260 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3262 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003263 for (i = 0 ; i < p->num_phys ; i++)
3264 mptsas_port_delete(p->phy_info[i].port_details);
3265 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266 kfree(p);
3267 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003268 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003269
3270 mptscsih_remove(pdev);
3271}
3272
3273static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003274 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003275 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003276 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003277 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003278 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003279 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003280 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003281 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003282 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003283 PCI_ANY_ID, PCI_ANY_ID },
3284 {0} /* Terminating entry */
3285};
3286MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3287
3288
3289static struct pci_driver mptsas_driver = {
3290 .name = "mptsas",
3291 .id_table = mptsas_pci_table,
3292 .probe = mptsas_probe,
3293 .remove = __devexit_p(mptsas_remove),
3294 .shutdown = mptscsih_shutdown,
3295#ifdef CONFIG_PM
3296 .suspend = mptscsih_suspend,
3297 .resume = mptscsih_resume,
3298#endif
3299};
3300
3301static int __init
3302mptsas_init(void)
3303{
3304 show_mptmod_ver(my_NAME, my_VERSION);
3305
3306 mptsas_transport_template =
3307 sas_attach_transport(&mptsas_transport_functions);
3308 if (!mptsas_transport_template)
3309 return -ENODEV;
3310
3311 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003312 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003313 mptsasInternalCtx =
3314 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003315 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003316
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003317 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07003318 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003319 ": Registered for IOC event notifications\n"));
3320 }
3321
Eric Mooredf9e0622007-01-29 09:46:21 -07003322 if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003323 dprintk((KERN_INFO MYNAM
3324 ": Registered for IOC reset notifications\n"));
3325 }
3326
3327 return pci_register_driver(&mptsas_driver);
3328}
3329
3330static void __exit
3331mptsas_exit(void)
3332{
3333 pci_unregister_driver(&mptsas_driver);
3334 sas_release_transport(mptsas_transport_template);
3335
3336 mpt_reset_deregister(mptsasDoneCtx);
3337 mpt_event_deregister(mptsasDoneCtx);
3338
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003339 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003340 mpt_deregister(mptsasInternalCtx);
3341 mpt_deregister(mptsasTaskCtx);
3342 mpt_deregister(mptsasDoneCtx);
3343}
3344
3345module_init(mptsas_init);
3346module_exit(mptsas_exit);