blob: 404c014db1bdaa30538a4f2fff0c25b2151f7e47 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
Eric Moore9f4203b2007-01-04 20:47:47 -07006 * Copyright (c) 1999-2007 LSI Logic Corporation
Eric Moore07c861d2007-01-29 09:48:50 -07007 * (mailto:mpt_linux_developer@lsi.com)
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 2005-2007 Dell
Christoph Hellwig0c33b272005-09-09 16:27:19 +02009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
64
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Christoph Hellwig0c33b272005-09-09 16:27:19 +020092static int mptsasDoneCtx = -1;
93static int mptsasTaskCtx = -1;
94static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020095static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020096
Eric Mooreb506ade2007-01-29 09:45:37 -070097static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Eric Mooredf9e0622007-01-29 09:46:21 -070099struct mptsas_target_reset_event {
100 struct list_head list;
101 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
102 u8 target_reset_issued;
103};
104
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100105enum mptsas_hotplug_action {
106 MPTSAS_ADD_DEVICE,
107 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -0700108 MPTSAS_ADD_RAID,
109 MPTSAS_DEL_RAID,
Eric Mooreb506ade2007-01-29 09:45:37 -0700110 MPTSAS_ADD_INACTIVE_VOLUME,
Moore, Ericbd23e942006-04-17 12:43:04 -0600111 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100112};
113
114struct mptsas_hotplug_event {
115 struct work_struct work;
116 MPT_ADAPTER *ioc;
117 enum mptsas_hotplug_action event_type;
118 u64 sas_address;
Eric Mooreb506ade2007-01-29 09:45:37 -0700119 u8 channel;
120 u8 id;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100121 u32 device_info;
122 u16 handle;
123 u16 parent_handle;
124 u8 phy_id;
Eric Mooreb506ade2007-01-29 09:45:37 -0700125 u8 phys_disk_num_valid; /* hrc (hidden raid component) */
126 u8 phys_disk_num; /* hrc - unique index*/
127 u8 hidden_raid_component; /* hrc - don't expose*/
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100128};
129
Moore, Erice6b2d762006-03-14 09:14:24 -0700130struct mptsas_discovery_event {
131 struct work_struct work;
132 MPT_ADAPTER *ioc;
133};
134
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200135/*
136 * SAS topology structures
137 *
138 * The MPT Fusion firmware interface spreads information about the
139 * SAS topology over many manufacture pages, thus we need some data
140 * structure to collect it and process it for the SAS transport class.
141 */
142
143struct mptsas_devinfo {
144 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700145 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100146 u16 handle_enclosure; /* enclosure identifier of the enclosure */
147 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200148 u8 phy_id; /* phy number of parent device */
149 u8 port_id; /* sas physical port this device
150 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100151 u8 id; /* logical target id of this device */
Eric Mooreb506ade2007-01-29 09:45:37 -0700152 u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100153 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200154 u64 sas_address; /* WWN of this device,
155 SATA is assigned by HBA,expander */
156 u32 device_info; /* bitfield detailed info about this device */
157};
158
Eric Moore547f9a22006-06-27 14:42:12 -0600159/*
160 * Specific details on ports, wide/narrow
161 */
162struct mptsas_portinfo_details{
Eric Moore547f9a22006-06-27 14:42:12 -0600163 u16 num_phys; /* number of phys belong to this port */
164 u64 phy_bitmask; /* TODO, extend support for 255 phys */
165 struct sas_rphy *rphy; /* transport layer rphy object */
166 struct sas_port *port; /* transport layer port object */
167 struct scsi_target *starget;
168 struct mptsas_portinfo *port_info;
169};
170
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200171struct mptsas_phyinfo {
Eric Moore2ecce492007-01-29 09:47:08 -0700172 u16 handle; /* unique id to address this */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200173 u8 phy_id; /* phy index */
Eric Moore547f9a22006-06-27 14:42:12 -0600174 u8 port_id; /* firmware port identifier */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200175 u8 negotiated_link_rate; /* nego'd link rate for this phy */
176 u8 hw_link_rate; /* hardware max/min phys link rate */
177 u8 programmed_link_rate; /* programmed max/min phy link rate */
Eric Moore547f9a22006-06-27 14:42:12 -0600178 u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200179 struct mptsas_devinfo identify; /* point to phy device info */
180 struct mptsas_devinfo attached; /* point to attached device info */
Eric Moore547f9a22006-06-27 14:42:12 -0600181 struct sas_phy *phy; /* transport layer phy object */
182 struct mptsas_portinfo *portinfo;
183 struct mptsas_portinfo_details * port_details;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200184};
185
186struct mptsas_portinfo {
187 struct list_head list;
Eric Moore547f9a22006-06-27 14:42:12 -0600188 u16 num_phys; /* number of phys */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200189 struct mptsas_phyinfo *phy_info;
190};
191
Christoph Hellwige3094442006-02-16 13:25:36 +0100192struct mptsas_enclosure {
193 u64 enclosure_logical_id; /* The WWN for the enclosure */
194 u16 enclosure_handle; /* unique id to address this */
195 u16 flags; /* details enclosure management */
196 u16 num_slot; /* num slots */
197 u16 start_slot; /* first slot */
198 u8 start_id; /* starting logical target id */
199 u8 start_channel; /* starting logical channel id */
200 u8 sep_id; /* SEP device logical target id */
201 u8 sep_channel; /* SEP channel logical channel id */
202};
203
Eric Moore547f9a22006-06-27 14:42:12 -0600204#ifdef MPT_DEBUG_SAS
Christoph Hellwigb5141122005-10-28 22:07:41 +0200205static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
206{
207 printk("---- IO UNIT PAGE 0 ------------\n");
208 printk("Handle=0x%X\n",
209 le16_to_cpu(phy_data->AttachedDeviceHandle));
210 printk("Controller Handle=0x%X\n",
211 le16_to_cpu(phy_data->ControllerDevHandle));
212 printk("Port=0x%X\n", phy_data->Port);
213 printk("Port Flags=0x%X\n", phy_data->PortFlags);
214 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
215 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
216 printk("Controller PHY Device Info=0x%X\n",
217 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
218 printk("DiscoveryStatus=0x%X\n",
219 le32_to_cpu(phy_data->DiscoveryStatus));
220 printk("\n");
221}
222
223static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
224{
225 __le64 sas_address;
226
227 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
228
229 printk("---- SAS PHY PAGE 0 ------------\n");
230 printk("Attached Device Handle=0x%X\n",
231 le16_to_cpu(pg0->AttachedDevHandle));
232 printk("SAS Address=0x%llX\n",
233 (unsigned long long)le64_to_cpu(sas_address));
234 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
235 printk("Attached Device Info=0x%X\n",
236 le32_to_cpu(pg0->AttachedDeviceInfo));
237 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
238 printk("Change Count=0x%X\n", pg0->ChangeCount);
239 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
240 printk("\n");
241}
242
243static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
244{
245 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200246 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
247 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200249 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
250 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
251 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252}
253
254static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
255{
256 __le64 sas_address;
257
258 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
259
260 printk("---- SAS DEVICE PAGE 0 ---------\n");
261 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100262 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200263 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
264 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
Eric Mooref99be432007-01-04 20:46:54 -0700265 printk("SAS Address=0x%llX\n", (unsigned long long)
266 le64_to_cpu(sas_address));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200267 printk("Target ID=0x%X\n", pg0->TargetID);
268 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200269 /* The PhyNum field specifies the PHY number of the parent
270 * device this device is linked to
271 */
272 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
273 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200274 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
275 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
276 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
277 printk("\n");
278}
279
280static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
281{
282 printk("---- SAS EXPANDER PAGE 1 ------------\n");
283
284 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200285 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200286 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
287 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
288 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
289 printk("Owner Device Handle=0x%X\n",
290 le16_to_cpu(pg1->OwnerDevHandle));
291 printk("Attached Device Handle=0x%X\n",
292 le16_to_cpu(pg1->AttachedDevHandle));
293}
294#else
295#define mptsas_print_phy_data(phy_data) do { } while (0)
296#define mptsas_print_phy_pg0(pg0) do { } while (0)
297#define mptsas_print_phy_pg1(pg1) do { } while (0)
298#define mptsas_print_device_pg0(pg0) do { } while (0)
299#define mptsas_print_expander_pg1(pg1) do { } while (0)
300#endif
301
Christoph Hellwige3094442006-02-16 13:25:36 +0100302static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
303{
304 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
305 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
306}
307
308static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
309{
310 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
311 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
312}
313
Moore, Erice6b2d762006-03-14 09:14:24 -0700314/*
315 * mptsas_find_portinfo_by_handle
316 *
317 * This function should be called with the sas_topology_mutex already held
318 */
319static struct mptsas_portinfo *
320mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
321{
322 struct mptsas_portinfo *port_info, *rc=NULL;
323 int i;
324
325 list_for_each_entry(port_info, &ioc->sas_topology, list)
326 for (i = 0; i < port_info->num_phys; i++)
327 if (port_info->phy_info[i].identify.handle == handle) {
328 rc = port_info;
329 goto out;
330 }
331 out:
332 return rc;
333}
334
Moore, Ericbd23e942006-04-17 12:43:04 -0600335/*
336 * Returns true if there is a scsi end device
337 */
338static inline int
339mptsas_is_end_device(struct mptsas_devinfo * attached)
340{
Eric Moore547f9a22006-06-27 14:42:12 -0600341 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600342 (attached->device_info &
343 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
344 ((attached->device_info &
345 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
346 (attached->device_info &
347 MPI_SAS_DEVICE_INFO_STP_TARGET) |
348 (attached->device_info &
349 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
350 return 1;
351 else
352 return 0;
353}
354
Eric Moore547f9a22006-06-27 14:42:12 -0600355/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600356static void
Eric Moore547f9a22006-06-27 14:42:12 -0600357mptsas_port_delete(struct mptsas_portinfo_details * port_details)
358{
359 struct mptsas_portinfo *port_info;
360 struct mptsas_phyinfo *phy_info;
361 u8 i;
362
363 if (!port_details)
364 return;
365
366 port_info = port_details->port_info;
367 phy_info = port_info->phy_info;
368
Eric Mooredc22f162006-07-06 11:23:14 -0600369 dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
Eric Mooref99be432007-01-04 20:46:54 -0700370 "bitmask=0x%016llX\n", __FUNCTION__, port_details,
371 port_details->num_phys, (unsigned long long)
372 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600373
374 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
375 if(phy_info->port_details != port_details)
376 continue;
377 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
378 phy_info->port_details = NULL;
379 }
380 kfree(port_details);
381}
382
383static inline struct sas_rphy *
384mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
385{
386 if (phy_info->port_details)
387 return phy_info->port_details->rphy;
388 else
389 return NULL;
390}
391
392static inline void
393mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
394{
395 if (phy_info->port_details) {
396 phy_info->port_details->rphy = rphy;
397 dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
398 }
399
400#ifdef MPT_DEBUG_SAS_WIDE
401 if (rphy) {
402 dev_printk(KERN_DEBUG, &rphy->dev, "add:");
403 printk("rphy=%p release=%p\n",
404 rphy, rphy->dev.release);
405 }
406#endif
407}
408
409static inline struct sas_port *
410mptsas_get_port(struct mptsas_phyinfo *phy_info)
411{
412 if (phy_info->port_details)
413 return phy_info->port_details->port;
414 else
415 return NULL;
416}
417
418static inline void
419mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
420{
421 if (phy_info->port_details)
422 phy_info->port_details->port = port;
423
424#ifdef MPT_DEBUG_SAS_WIDE
425 if (port) {
426 dev_printk(KERN_DEBUG, &port->dev, "add: ");
427 printk("port=%p release=%p\n",
428 port, port->dev.release);
429 }
430#endif
431}
432
433static inline struct scsi_target *
434mptsas_get_starget(struct mptsas_phyinfo *phy_info)
435{
436 if (phy_info->port_details)
437 return phy_info->port_details->starget;
438 else
439 return NULL;
440}
441
442static inline void
443mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
444starget)
445{
446 if (phy_info->port_details)
447 phy_info->port_details->starget = starget;
448}
449
450
451/*
452 * mptsas_setup_wide_ports
453 *
454 * Updates for new and existing narrow/wide port configuration
455 * in the sas_topology
456 */
Eric Moore376ac832006-06-29 17:36:26 -0600457static void
Eric Moore547f9a22006-06-27 14:42:12 -0600458mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
459{
460 struct mptsas_portinfo_details * port_details;
461 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
462 u64 sas_address;
463 int i, j;
464
465 mutex_lock(&ioc->sas_topology_mutex);
466
467 phy_info = port_info->phy_info;
468 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
469 if (phy_info->attached.handle)
470 continue;
471 port_details = phy_info->port_details;
472 if (!port_details)
473 continue;
474 if (port_details->num_phys < 2)
475 continue;
476 /*
477 * Removing a phy from a port, letting the last
478 * phy be removed by firmware events.
479 */
480 dsaswideprintk((KERN_DEBUG
Eric Mooredc22f162006-07-06 11:23:14 -0600481 "%s: [%p]: deleting phy = %d\n",
482 __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600483 port_details->num_phys--;
484 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
485 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
486 sas_port_delete_phy(port_details->port, phy_info->phy);
487 phy_info->port_details = NULL;
488 }
489
490 /*
491 * Populate and refresh the tree
492 */
493 phy_info = port_info->phy_info;
494 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
495 sas_address = phy_info->attached.sas_address;
496 dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
Eric Mooref99be432007-01-04 20:46:54 -0700497 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600498 if (!sas_address)
499 continue;
500 port_details = phy_info->port_details;
501 /*
502 * Forming a port
503 */
504 if (!port_details) {
505 port_details = kzalloc(sizeof(*port_details),
506 GFP_KERNEL);
507 if (!port_details)
508 goto out;
509 port_details->num_phys = 1;
510 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600511 if (phy_info->phy_id < 64 )
512 port_details->phy_bitmask |=
513 (1 << phy_info->phy_id);
514 phy_info->sas_port_add_phy=1;
515 dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700516 "phy_id=%d sas_address=0x%018llX\n",
517 i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600518 phy_info->port_details = port_details;
519 }
520
521 if (i == port_info->num_phys - 1)
522 continue;
523 phy_info_cmp = &port_info->phy_info[i + 1];
524 for (j = i + 1 ; j < port_info->num_phys ; j++,
525 phy_info_cmp++) {
526 if (!phy_info_cmp->attached.sas_address)
527 continue;
528 if (sas_address != phy_info_cmp->attached.sas_address)
529 continue;
530 if (phy_info_cmp->port_details == port_details )
531 continue;
532 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700533 "\t\tphy_id=%d sas_address=0x%018llX\n",
534 j, (unsigned long long)
535 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600536 if (phy_info_cmp->port_details) {
537 port_details->rphy =
538 mptsas_get_rphy(phy_info_cmp);
539 port_details->port =
540 mptsas_get_port(phy_info_cmp);
541 port_details->starget =
542 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600543 port_details->num_phys =
544 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600545 if (!phy_info_cmp->port_details->num_phys)
546 kfree(phy_info_cmp->port_details);
547 } else
548 phy_info_cmp->sas_port_add_phy=1;
549 /*
550 * Adding a phy to a port
551 */
552 phy_info_cmp->port_details = port_details;
553 if (phy_info_cmp->phy_id < 64 )
554 port_details->phy_bitmask |=
555 (1 << phy_info_cmp->phy_id);
556 port_details->num_phys++;
557 }
558 }
559
560 out:
561
562#ifdef MPT_DEBUG_SAS_WIDE
563 for (i = 0; i < port_info->num_phys; i++) {
564 port_details = port_info->phy_info[i].port_details;
565 if (!port_details)
566 continue;
567 dsaswideprintk((KERN_DEBUG
Eric Mooref99be432007-01-04 20:46:54 -0700568 "%s: [%p]: phy_id=%02d num_phys=%02d "
569 "bitmask=0x%016llX\n", __FUNCTION__,
570 port_details, i, port_details->num_phys,
571 (unsigned long long)port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600572 dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
573 port_details->port, port_details->rphy));
574 }
575 dsaswideprintk((KERN_DEBUG"\n"));
576#endif
577 mutex_unlock(&ioc->sas_topology_mutex);
578}
579
Eric Mooredf9e0622007-01-29 09:46:21 -0700580/**
581 * csmisas_find_vtarget
582 *
583 * @ioc
584 * @volume_id
585 * @volume_bus
586 *
587 **/
588static VirtTarget *
589mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600590{
Eric Mooredf9e0622007-01-29 09:46:21 -0700591 struct scsi_device *sdev;
592 VirtDevice *vdev;
593 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600594
Eric Mooredf9e0622007-01-29 09:46:21 -0700595 shost_for_each_device(sdev, ioc->sh) {
596 if ((vdev = sdev->hostdata) == NULL)
597 continue;
598 if (vdev->vtarget->id == id &&
599 vdev->vtarget->channel == channel)
600 vtarget = vdev->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600601 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700602 return vtarget;
603}
604
605/**
606 * mptsas_target_reset
607 *
608 * Issues TARGET_RESET to end device using handshaking method
609 *
610 * @ioc
611 * @channel
612 * @id
613 *
614 * Returns (1) success
615 * (0) failure
616 *
617 **/
618static int
619mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
620{
621 MPT_FRAME_HDR *mf;
622 SCSITaskMgmt_t *pScsiTm;
623
624 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
625 dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
626 ioc->name,__FUNCTION__, __LINE__));
627 return 0;
628 }
629
630 /* Format the Request
631 */
632 pScsiTm = (SCSITaskMgmt_t *) mf;
633 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
634 pScsiTm->TargetID = id;
635 pScsiTm->Bus = channel;
636 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
637 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
638 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
639
640 DBG_DUMP_TM_REQUEST_FRAME(mf);
641
642 if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
643 sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
644 mpt_free_msg_frame(ioc, mf);
645 dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
646 ioc->name,__FUNCTION__, __LINE__));
647 return 0;
648 }
649
650 return 1;
651}
652
653/**
654 * mptsas_target_reset_queue
655 *
656 * Receive request for TARGET_RESET after recieving an firmware
657 * event NOT_RESPONDING_EVENT, then put command in link list
658 * and queue if task_queue already in use.
659 *
660 * @ioc
661 * @sas_event_data
662 *
663 **/
664static void
665mptsas_target_reset_queue(MPT_ADAPTER *ioc,
666 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
667{
668 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
669 VirtTarget *vtarget = NULL;
670 struct mptsas_target_reset_event *target_reset_list;
671 u8 id, channel;
672
673 id = sas_event_data->TargetID;
674 channel = sas_event_data->Bus;
675
676 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
677 return;
678
679 vtarget->deleted = 1; /* block IO */
680
681 target_reset_list = kzalloc(sizeof(*target_reset_list),
682 GFP_ATOMIC);
683 if (!target_reset_list) {
684 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
685 ioc->name,__FUNCTION__, __LINE__));
686 return;
687 }
688
689 memcpy(&target_reset_list->sas_event_data, sas_event_data,
690 sizeof(*sas_event_data));
691 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
692
693 if (hd->resetPending)
694 return;
695
696 if (mptsas_target_reset(ioc, channel, id)) {
697 target_reset_list->target_reset_issued = 1;
698 hd->resetPending = 1;
699 }
700}
701
702/**
703 * mptsas_dev_reset_complete
704 *
705 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
706 * enable work queue to finish off removing device from upper layers.
707 * then send next TARGET_RESET in the queue.
708 *
709 * @ioc
710 *
711 **/
712static void
713mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
714{
715 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
716 struct list_head *head = &hd->target_reset_list;
717 struct mptsas_target_reset_event *target_reset_list;
718 struct mptsas_hotplug_event *ev;
719 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
720 u8 id, channel;
721 __le64 sas_address;
722
723 if (list_empty(head))
724 return;
725
726 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
727
728 sas_event_data = &target_reset_list->sas_event_data;
729 id = sas_event_data->TargetID;
730 channel = sas_event_data->Bus;
731 hd->resetPending = 0;
732
733 /*
734 * retry target reset
735 */
736 if (!target_reset_list->target_reset_issued) {
737 if (mptsas_target_reset(ioc, channel, id)) {
738 target_reset_list->target_reset_issued = 1;
739 hd->resetPending = 1;
740 }
741 return;
742 }
743
744 /*
745 * enable work queue to remove device from upper layers
746 */
747 list_del(&target_reset_list->list);
748
749 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
750 if (!ev) {
751 dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
752 ioc->name,__FUNCTION__, __LINE__));
753 return;
754 }
755
756 INIT_WORK(&ev->work, mptsas_hotplug_work);
757 ev->ioc = ioc;
758 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
759 ev->parent_handle =
760 le16_to_cpu(sas_event_data->ParentDevHandle);
761 ev->channel = channel;
762 ev->id =id;
763 ev->phy_id = sas_event_data->PhyNum;
764 memcpy(&sas_address, &sas_event_data->SASAddress,
765 sizeof(__le64));
766 ev->sas_address = le64_to_cpu(sas_address);
767 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
768 ev->event_type = MPTSAS_DEL_DEVICE;
769 schedule_work(&ev->work);
770 kfree(target_reset_list);
771
772 /*
773 * issue target reset to next device in the queue
774 */
775
776 head = &hd->target_reset_list;
777 if (list_empty(head))
778 return;
779
780 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
781 list);
782
783 sas_event_data = &target_reset_list->sas_event_data;
784 id = sas_event_data->TargetID;
785 channel = sas_event_data->Bus;
786
787 if (mptsas_target_reset(ioc, channel, id)) {
788 target_reset_list->target_reset_issued = 1;
789 hd->resetPending = 1;
790 }
791}
792
793/**
794 * mptsas_taskmgmt_complete
795 *
796 * @ioc
797 * @mf
798 * @mr
799 *
800 **/
801static int
802mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
803{
804 mptsas_dev_reset_complete(ioc);
805 return mptscsih_taskmgmt_complete(ioc, mf, mr);
806}
807
808/**
809 * mptscsih_ioc_reset
810 *
811 * @ioc
812 * @reset_phase
813 *
814 **/
815static int
816mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
817{
818 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
819 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
830 if (!hd || !hd->ioc)
831 goto out;
832
833 if (list_empty(&hd->target_reset_list))
834 goto out;
835
836 /* flush the target_reset_list */
837 list_for_each_entry_safe(target_reset_list, n,
838 &hd->target_reset_list, list) {
839 list_del(&target_reset_list->list);
840 kfree(target_reset_list);
841 }
842
843 out:
844 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600845}
846
Christoph Hellwige3094442006-02-16 13:25:36 +0100847static int
Moore, Eric52435432006-03-14 09:14:15 -0700848mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100849 u32 form, u32 form_specific)
850{
851 ConfigExtendedPageHeader_t hdr;
852 CONFIGPARMS cfg;
853 SasEnclosurePage0_t *buffer;
854 dma_addr_t dma_handle;
855 int error;
856 __le64 le_identifier;
857
858 memset(&hdr, 0, sizeof(hdr));
859 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
860 hdr.PageNumber = 0;
861 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
862 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
863
864 cfg.cfghdr.ehdr = &hdr;
865 cfg.physAddr = -1;
866 cfg.pageAddr = form + form_specific;
867 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
868 cfg.dir = 0; /* read */
869 cfg.timeout = 10;
870
871 error = mpt_config(ioc, &cfg);
872 if (error)
873 goto out;
874 if (!hdr.ExtPageLength) {
875 error = -ENXIO;
876 goto out;
877 }
878
879 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
880 &dma_handle);
881 if (!buffer) {
882 error = -ENOMEM;
883 goto out;
884 }
885
886 cfg.physAddr = dma_handle;
887 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
888
889 error = mpt_config(ioc, &cfg);
890 if (error)
891 goto out_free_consistent;
892
893 /* save config data */
894 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
895 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
896 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
897 enclosure->flags = le16_to_cpu(buffer->Flags);
898 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
899 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
900 enclosure->start_id = buffer->StartTargetID;
901 enclosure->start_channel = buffer->StartBus;
902 enclosure->sep_id = buffer->SEPTargetID;
903 enclosure->sep_channel = buffer->SEPBus;
904
905 out_free_consistent:
906 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
907 buffer, dma_handle);
908 out:
909 return error;
910}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200911
James Bottomleyf013db32006-03-18 14:54:36 -0600912static int
913mptsas_slave_configure(struct scsi_device *sdev)
914{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600915
James Bottomleye8bf3942006-07-11 17:49:34 -0400916 if (sdev->channel == MPTSAS_RAID_CHANNEL)
917 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600918
James Bottomleye8bf3942006-07-11 17:49:34 -0400919 sas_read_port_mode_page(sdev);
920
921 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600922 return mptscsih_slave_configure(sdev);
923}
924
Eric Moore547f9a22006-06-27 14:42:12 -0600925static int
926mptsas_target_alloc(struct scsi_target *starget)
927{
928 struct Scsi_Host *host = dev_to_shost(&starget->dev);
929 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
930 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700931 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600932 struct sas_rphy *rphy;
933 struct mptsas_portinfo *p;
934 int i;
935
936 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
937 if (!vtarget)
938 return -ENOMEM;
939
940 vtarget->starget = starget;
941 vtarget->ioc_id = hd->ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700942 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
943 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600944 channel = 0;
945
Eric Moore793955f2007-01-29 09:42:20 -0700946 /*
947 * RAID volumes placed beyond the last expected port.
948 */
949 if (starget->channel == MPTSAS_RAID_CHANNEL) {
950 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
951 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
952 channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600953 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700954 }
Eric Moore547f9a22006-06-27 14:42:12 -0600955
956 rphy = dev_to_rphy(starget->dev.parent);
957 mutex_lock(&hd->ioc->sas_topology_mutex);
958 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
959 for (i = 0; i < p->num_phys; i++) {
960 if (p->phy_info[i].attached.sas_address !=
961 rphy->identify.sas_address)
962 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700963 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600964 channel = p->phy_info[i].attached.channel;
965 mptsas_set_starget(&p->phy_info[i], starget);
966
967 /*
968 * Exposing hidden raid components
969 */
Eric Moore793955f2007-01-29 09:42:20 -0700970 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
971 id = mptscsih_raid_id_to_num(hd->ioc,
972 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600973 vtarget->tflags |=
974 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700975 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600976 }
977 mutex_unlock(&hd->ioc->sas_topology_mutex);
978 goto out;
979 }
980 }
981 mutex_unlock(&hd->ioc->sas_topology_mutex);
982
983 kfree(vtarget);
984 return -ENXIO;
985
986 out:
Eric Moore793955f2007-01-29 09:42:20 -0700987 vtarget->id = id;
988 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600989 starget->hostdata = vtarget;
990 return 0;
991}
992
993static void
994mptsas_target_destroy(struct scsi_target *starget)
995{
996 struct Scsi_Host *host = dev_to_shost(&starget->dev);
997 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
998 struct sas_rphy *rphy;
999 struct mptsas_portinfo *p;
1000 int i;
1001
1002 if (!starget->hostdata)
1003 return;
1004
James Bottomleye8bf3942006-07-11 17:49:34 -04001005 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001006 goto out;
1007
1008 rphy = dev_to_rphy(starget->dev.parent);
1009 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1010 for (i = 0; i < p->num_phys; i++) {
1011 if (p->phy_info[i].attached.sas_address !=
1012 rphy->identify.sas_address)
1013 continue;
1014 mptsas_set_starget(&p->phy_info[i], NULL);
1015 goto out;
1016 }
1017 }
1018
1019 out:
1020 kfree(starget->hostdata);
1021 starget->hostdata = NULL;
1022}
1023
1024
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001025static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001026mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001027{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001028 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001029 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
1030 struct sas_rphy *rphy;
1031 struct mptsas_portinfo *p;
1032 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001033 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001034 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001035
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01001036 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001037 if (!vdev) {
Eric Moore547f9a22006-06-27 14:42:12 -06001038 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001039 hd->ioc->name, sizeof(VirtDevice));
1040 return -ENOMEM;
1041 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001042 starget = scsi_target(sdev);
Eric Moore547f9a22006-06-27 14:42:12 -06001043 vdev->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001044
James Bottomleye8bf3942006-07-11 17:49:34 -04001045 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001046 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001047
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001048 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001049 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001050 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
1051 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001052 if (p->phy_info[i].attached.sas_address !=
1053 rphy->identify.sas_address)
1054 continue;
1055 vdev->lun = sdev->lun;
1056 /*
1057 * Exposing hidden raid components
1058 */
1059 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001060 p->phy_info[i].attached.channel,
1061 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001062 sdev->no_uld_attach = 1;
1063 mutex_unlock(&hd->ioc->sas_topology_mutex);
1064 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001065 }
1066 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001067 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001068
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001069 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001070 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001071
1072 out:
Eric Moore547f9a22006-06-27 14:42:12 -06001073 vdev->vtarget->num_luns++;
1074 sdev->hostdata = vdev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001075 return 0;
1076}
1077
Eric Moore547f9a22006-06-27 14:42:12 -06001078static int
1079mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001080{
Eric Moore547f9a22006-06-27 14:42:12 -06001081 VirtDevice *vdev = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001082
Eric Moore793955f2007-01-29 09:42:20 -07001083 if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001084 SCpnt->result = DID_NO_CONNECT << 16;
1085 done(SCpnt);
1086 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001087 }
Eric Moore547f9a22006-06-27 14:42:12 -06001088
Eric Moore793955f2007-01-29 09:42:20 -07001089// scsi_print_command(SCpnt);
1090
Eric Moore547f9a22006-06-27 14:42:12 -06001091 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001092}
1093
Eric Moore547f9a22006-06-27 14:42:12 -06001094
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001095static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001096 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001097 .proc_name = "mptsas",
1098 .proc_info = mptscsih_proc_info,
1099 .name = "MPT SPI Host",
1100 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001101 .queuecommand = mptsas_qcmd,
1102 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001103 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001104 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001105 .target_destroy = mptsas_target_destroy,
1106 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001107 .change_queue_depth = mptscsih_change_queue_depth,
1108 .eh_abort_handler = mptscsih_abort,
1109 .eh_device_reset_handler = mptscsih_dev_reset,
1110 .eh_bus_reset_handler = mptscsih_bus_reset,
1111 .eh_host_reset_handler = mptscsih_host_reset,
1112 .bios_param = mptscsih_bios_param,
1113 .can_queue = MPT_FC_CAN_QUEUE,
1114 .this_id = -1,
1115 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1116 .max_sectors = 8192,
1117 .cmd_per_lun = 7,
1118 .use_clustering = ENABLE_CLUSTERING,
1119};
1120
Christoph Hellwigb5141122005-10-28 22:07:41 +02001121static int mptsas_get_linkerrors(struct sas_phy *phy)
1122{
1123 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1124 ConfigExtendedPageHeader_t hdr;
1125 CONFIGPARMS cfg;
1126 SasPhyPage1_t *buffer;
1127 dma_addr_t dma_handle;
1128 int error;
1129
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001130 /* FIXME: only have link errors on local phys */
1131 if (!scsi_is_sas_phy_local(phy))
1132 return -EINVAL;
1133
Christoph Hellwigb5141122005-10-28 22:07:41 +02001134 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1135 hdr.ExtPageLength = 0;
1136 hdr.PageNumber = 1 /* page number 1*/;
1137 hdr.Reserved1 = 0;
1138 hdr.Reserved2 = 0;
1139 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1140 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1141
1142 cfg.cfghdr.ehdr = &hdr;
1143 cfg.physAddr = -1;
1144 cfg.pageAddr = phy->identify.phy_identifier;
1145 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1146 cfg.dir = 0; /* read */
1147 cfg.timeout = 10;
1148
1149 error = mpt_config(ioc, &cfg);
1150 if (error)
1151 return error;
1152 if (!hdr.ExtPageLength)
1153 return -ENXIO;
1154
1155 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1156 &dma_handle);
1157 if (!buffer)
1158 return -ENOMEM;
1159
1160 cfg.physAddr = dma_handle;
1161 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1162
1163 error = mpt_config(ioc, &cfg);
1164 if (error)
1165 goto out_free_consistent;
1166
1167 mptsas_print_phy_pg1(buffer);
1168
1169 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1170 phy->running_disparity_error_count =
1171 le32_to_cpu(buffer->RunningDisparityErrorCount);
1172 phy->loss_of_dword_sync_count =
1173 le32_to_cpu(buffer->LossDwordSynchCount);
1174 phy->phy_reset_problem_count =
1175 le32_to_cpu(buffer->PhyResetProblemCount);
1176
1177 out_free_consistent:
1178 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1179 buffer, dma_handle);
1180 return error;
1181}
1182
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001183static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1184 MPT_FRAME_HDR *reply)
1185{
1186 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1187 if (reply != NULL) {
1188 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1189 memcpy(ioc->sas_mgmt.reply, reply,
1190 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1191 }
1192 complete(&ioc->sas_mgmt.done);
1193 return 1;
1194}
1195
1196static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1197{
1198 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1199 SasIoUnitControlRequest_t *req;
1200 SasIoUnitControlReply_t *reply;
1201 MPT_FRAME_HDR *mf;
1202 MPIHeader_t *hdr;
1203 unsigned long timeleft;
1204 int error = -ERESTARTSYS;
1205
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001206 /* FIXME: fusion doesn't allow non-local phy reset */
1207 if (!scsi_is_sas_phy_local(phy))
1208 return -EINVAL;
1209
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001210 /* not implemented for expanders */
1211 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1212 return -ENXIO;
1213
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001214 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001215 goto out;
1216
1217 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1218 if (!mf) {
1219 error = -ENOMEM;
1220 goto out_unlock;
1221 }
1222
1223 hdr = (MPIHeader_t *) mf;
1224 req = (SasIoUnitControlRequest_t *)mf;
1225 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1226 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1227 req->MsgContext = hdr->MsgContext;
1228 req->Operation = hard_reset ?
1229 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1230 req->PhyNum = phy->identify.phy_identifier;
1231
1232 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1233
1234 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1235 10 * HZ);
1236 if (!timeleft) {
1237 /* On timeout reset the board */
1238 mpt_free_msg_frame(ioc, mf);
1239 mpt_HardResetHandler(ioc, CAN_SLEEP);
1240 error = -ETIMEDOUT;
1241 goto out_unlock;
1242 }
1243
1244 /* a reply frame is expected */
1245 if ((ioc->sas_mgmt.status &
1246 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1247 error = -ENXIO;
1248 goto out_unlock;
1249 }
1250
1251 /* process the completed Reply Message Frame */
1252 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1253 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
1254 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1255 __FUNCTION__,
1256 reply->IOCStatus,
1257 reply->IOCLogInfo);
1258 error = -ENXIO;
1259 goto out_unlock;
1260 }
1261
1262 error = 0;
1263
1264 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001265 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001266 out:
1267 return error;
1268}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001269
Christoph Hellwige3094442006-02-16 13:25:36 +01001270static int
1271mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1272{
1273 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1274 int i, error;
1275 struct mptsas_portinfo *p;
1276 struct mptsas_enclosure enclosure_info;
1277 u64 enclosure_handle;
1278
1279 mutex_lock(&ioc->sas_topology_mutex);
1280 list_for_each_entry(p, &ioc->sas_topology, list) {
1281 for (i = 0; i < p->num_phys; i++) {
1282 if (p->phy_info[i].attached.sas_address ==
1283 rphy->identify.sas_address) {
1284 enclosure_handle = p->phy_info[i].
1285 attached.handle_enclosure;
1286 goto found_info;
1287 }
1288 }
1289 }
1290 mutex_unlock(&ioc->sas_topology_mutex);
1291 return -ENXIO;
1292
1293 found_info:
1294 mutex_unlock(&ioc->sas_topology_mutex);
1295 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001296 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001297 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1298 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1299 if (!error)
1300 *identifier = enclosure_info.enclosure_logical_id;
1301 return error;
1302}
1303
1304static int
1305mptsas_get_bay_identifier(struct sas_rphy *rphy)
1306{
1307 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1308 struct mptsas_portinfo *p;
1309 int i, rc;
1310
1311 mutex_lock(&ioc->sas_topology_mutex);
1312 list_for_each_entry(p, &ioc->sas_topology, list) {
1313 for (i = 0; i < p->num_phys; i++) {
1314 if (p->phy_info[i].attached.sas_address ==
1315 rphy->identify.sas_address) {
1316 rc = p->phy_info[i].attached.slot;
1317 goto out;
1318 }
1319 }
1320 }
1321 rc = -ENXIO;
1322 out:
1323 mutex_unlock(&ioc->sas_topology_mutex);
1324 return rc;
1325}
1326
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001327static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001328 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001329 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1330 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001331 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001332};
1333
1334static struct scsi_transport_template *mptsas_transport_template;
1335
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001336static int
1337mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1338{
1339 ConfigExtendedPageHeader_t hdr;
1340 CONFIGPARMS cfg;
1341 SasIOUnitPage0_t *buffer;
1342 dma_addr_t dma_handle;
1343 int error, i;
1344
1345 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1346 hdr.ExtPageLength = 0;
1347 hdr.PageNumber = 0;
1348 hdr.Reserved1 = 0;
1349 hdr.Reserved2 = 0;
1350 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1351 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1352
1353 cfg.cfghdr.ehdr = &hdr;
1354 cfg.physAddr = -1;
1355 cfg.pageAddr = 0;
1356 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1357 cfg.dir = 0; /* read */
1358 cfg.timeout = 10;
1359
1360 error = mpt_config(ioc, &cfg);
1361 if (error)
1362 goto out;
1363 if (!hdr.ExtPageLength) {
1364 error = -ENXIO;
1365 goto out;
1366 }
1367
1368 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1369 &dma_handle);
1370 if (!buffer) {
1371 error = -ENOMEM;
1372 goto out;
1373 }
1374
1375 cfg.physAddr = dma_handle;
1376 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1377
1378 error = mpt_config(ioc, &cfg);
1379 if (error)
1380 goto out_free_consistent;
1381
1382 port_info->num_phys = buffer->NumPhys;
1383 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001384 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001385 if (!port_info->phy_info) {
1386 error = -ENOMEM;
1387 goto out_free_consistent;
1388 }
1389
1390 for (i = 0; i < port_info->num_phys; i++) {
1391 mptsas_print_phy_data(&buffer->PhyData[i]);
1392 port_info->phy_info[i].phy_id = i;
1393 port_info->phy_info[i].port_id =
1394 buffer->PhyData[i].Port;
1395 port_info->phy_info[i].negotiated_link_rate =
1396 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001397 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001398 port_info->phy_info[i].handle =
1399 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001400 }
1401
1402 out_free_consistent:
1403 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1404 buffer, dma_handle);
1405 out:
1406 return error;
1407}
1408
1409static int
1410mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1411 u32 form, u32 form_specific)
1412{
1413 ConfigExtendedPageHeader_t hdr;
1414 CONFIGPARMS cfg;
1415 SasPhyPage0_t *buffer;
1416 dma_addr_t dma_handle;
1417 int error;
1418
1419 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1420 hdr.ExtPageLength = 0;
1421 hdr.PageNumber = 0;
1422 hdr.Reserved1 = 0;
1423 hdr.Reserved2 = 0;
1424 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1425 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1426
1427 cfg.cfghdr.ehdr = &hdr;
1428 cfg.dir = 0; /* read */
1429 cfg.timeout = 10;
1430
1431 /* Get Phy Pg 0 for each Phy. */
1432 cfg.physAddr = -1;
1433 cfg.pageAddr = form + form_specific;
1434 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1435
1436 error = mpt_config(ioc, &cfg);
1437 if (error)
1438 goto out;
1439
1440 if (!hdr.ExtPageLength) {
1441 error = -ENXIO;
1442 goto out;
1443 }
1444
1445 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1446 &dma_handle);
1447 if (!buffer) {
1448 error = -ENOMEM;
1449 goto out;
1450 }
1451
1452 cfg.physAddr = dma_handle;
1453 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1454
1455 error = mpt_config(ioc, &cfg);
1456 if (error)
1457 goto out_free_consistent;
1458
1459 mptsas_print_phy_pg0(buffer);
1460
1461 phy_info->hw_link_rate = buffer->HwLinkRate;
1462 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1463 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1464 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1465
1466 out_free_consistent:
1467 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1468 buffer, dma_handle);
1469 out:
1470 return error;
1471}
1472
1473static int
1474mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1475 u32 form, u32 form_specific)
1476{
1477 ConfigExtendedPageHeader_t hdr;
1478 CONFIGPARMS cfg;
1479 SasDevicePage0_t *buffer;
1480 dma_addr_t dma_handle;
1481 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001482 int error=0;
1483
1484 if (ioc->sas_discovery_runtime &&
1485 mptsas_is_end_device(device_info))
1486 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001487
1488 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1489 hdr.ExtPageLength = 0;
1490 hdr.PageNumber = 0;
1491 hdr.Reserved1 = 0;
1492 hdr.Reserved2 = 0;
1493 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1494 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1495
1496 cfg.cfghdr.ehdr = &hdr;
1497 cfg.pageAddr = form + form_specific;
1498 cfg.physAddr = -1;
1499 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1500 cfg.dir = 0; /* read */
1501 cfg.timeout = 10;
1502
Moore, Ericdb9c9172006-03-14 09:14:18 -07001503 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001504 error = mpt_config(ioc, &cfg);
1505 if (error)
1506 goto out;
1507 if (!hdr.ExtPageLength) {
1508 error = -ENXIO;
1509 goto out;
1510 }
1511
1512 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1513 &dma_handle);
1514 if (!buffer) {
1515 error = -ENOMEM;
1516 goto out;
1517 }
1518
1519 cfg.physAddr = dma_handle;
1520 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1521
1522 error = mpt_config(ioc, &cfg);
1523 if (error)
1524 goto out_free_consistent;
1525
1526 mptsas_print_device_pg0(buffer);
1527
1528 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001529 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001530 device_info->handle_enclosure =
1531 le16_to_cpu(buffer->EnclosureHandle);
1532 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001533 device_info->phy_id = buffer->PhyNum;
1534 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001535 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001536 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001537 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001538 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1539 device_info->sas_address = le64_to_cpu(sas_address);
1540 device_info->device_info =
1541 le32_to_cpu(buffer->DeviceInfo);
1542
1543 out_free_consistent:
1544 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1545 buffer, dma_handle);
1546 out:
1547 return error;
1548}
1549
1550static int
1551mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1552 u32 form, u32 form_specific)
1553{
1554 ConfigExtendedPageHeader_t hdr;
1555 CONFIGPARMS cfg;
1556 SasExpanderPage0_t *buffer;
1557 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001558 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001559
1560 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1561 hdr.ExtPageLength = 0;
1562 hdr.PageNumber = 0;
1563 hdr.Reserved1 = 0;
1564 hdr.Reserved2 = 0;
1565 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1566 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1567
1568 cfg.cfghdr.ehdr = &hdr;
1569 cfg.physAddr = -1;
1570 cfg.pageAddr = form + form_specific;
1571 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1572 cfg.dir = 0; /* read */
1573 cfg.timeout = 10;
1574
Moore, Ericdb9c9172006-03-14 09:14:18 -07001575 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001576 error = mpt_config(ioc, &cfg);
1577 if (error)
1578 goto out;
1579
1580 if (!hdr.ExtPageLength) {
1581 error = -ENXIO;
1582 goto out;
1583 }
1584
1585 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1586 &dma_handle);
1587 if (!buffer) {
1588 error = -ENOMEM;
1589 goto out;
1590 }
1591
1592 cfg.physAddr = dma_handle;
1593 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1594
1595 error = mpt_config(ioc, &cfg);
1596 if (error)
1597 goto out_free_consistent;
1598
1599 /* save config data */
1600 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001601 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001602 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001603 if (!port_info->phy_info) {
1604 error = -ENOMEM;
1605 goto out_free_consistent;
1606 }
1607
Eric Moore2ecce492007-01-29 09:47:08 -07001608 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001609 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001610 port_info->phy_info[i].handle =
1611 le16_to_cpu(buffer->DevHandle);
1612 }
Eric Moore547f9a22006-06-27 14:42:12 -06001613
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001614 out_free_consistent:
1615 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1616 buffer, dma_handle);
1617 out:
1618 return error;
1619}
1620
1621static int
1622mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1623 u32 form, u32 form_specific)
1624{
1625 ConfigExtendedPageHeader_t hdr;
1626 CONFIGPARMS cfg;
1627 SasExpanderPage1_t *buffer;
1628 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001629 int error=0;
1630
1631 if (ioc->sas_discovery_runtime &&
1632 mptsas_is_end_device(&phy_info->attached))
1633 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001634
1635 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1636 hdr.ExtPageLength = 0;
1637 hdr.PageNumber = 1;
1638 hdr.Reserved1 = 0;
1639 hdr.Reserved2 = 0;
1640 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1641 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1642
1643 cfg.cfghdr.ehdr = &hdr;
1644 cfg.physAddr = -1;
1645 cfg.pageAddr = form + form_specific;
1646 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1647 cfg.dir = 0; /* read */
1648 cfg.timeout = 10;
1649
1650 error = mpt_config(ioc, &cfg);
1651 if (error)
1652 goto out;
1653
1654 if (!hdr.ExtPageLength) {
1655 error = -ENXIO;
1656 goto out;
1657 }
1658
1659 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1660 &dma_handle);
1661 if (!buffer) {
1662 error = -ENOMEM;
1663 goto out;
1664 }
1665
1666 cfg.physAddr = dma_handle;
1667 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1668
1669 error = mpt_config(ioc, &cfg);
1670 if (error)
1671 goto out_free_consistent;
1672
1673
1674 mptsas_print_expander_pg1(buffer);
1675
1676 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001677 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001678 phy_info->port_id = buffer->PhysicalPort;
1679 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1680 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1681 phy_info->hw_link_rate = buffer->HwLinkRate;
1682 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1683 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1684
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001685 out_free_consistent:
1686 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1687 buffer, dma_handle);
1688 out:
1689 return error;
1690}
1691
1692static void
1693mptsas_parse_device_info(struct sas_identify *identify,
1694 struct mptsas_devinfo *device_info)
1695{
1696 u16 protocols;
1697
1698 identify->sas_address = device_info->sas_address;
1699 identify->phy_identifier = device_info->phy_id;
1700
1701 /*
1702 * Fill in Phy Initiator Port Protocol.
1703 * Bits 6:3, more than one bit can be set, fall through cases.
1704 */
1705 protocols = device_info->device_info & 0x78;
1706 identify->initiator_port_protocols = 0;
1707 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1708 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1709 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1710 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1711 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1712 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1713 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1714 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1715
1716 /*
1717 * Fill in Phy Target Port Protocol.
1718 * Bits 10:7, more than one bit can be set, fall through cases.
1719 */
1720 protocols = device_info->device_info & 0x780;
1721 identify->target_port_protocols = 0;
1722 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1723 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1724 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1725 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1726 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1727 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1728 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1729 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1730
1731 /*
1732 * Fill in Attached device type.
1733 */
1734 switch (device_info->device_info &
1735 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1736 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1737 identify->device_type = SAS_PHY_UNUSED;
1738 break;
1739 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1740 identify->device_type = SAS_END_DEVICE;
1741 break;
1742 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1743 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1744 break;
1745 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1746 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1747 break;
1748 }
1749}
1750
1751static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001752 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001753{
Moore, Erice6b2d762006-03-14 09:14:24 -07001754 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001755 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001756 struct sas_port *port;
1757 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001758
Eric Moore547f9a22006-06-27 14:42:12 -06001759 if (!dev) {
1760 error = -ENODEV;
1761 goto out;
1762 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001763
1764 if (!phy_info->phy) {
1765 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001766 if (!phy) {
1767 error = -ENOMEM;
1768 goto out;
1769 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001770 } else
1771 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001772
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001773 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001774
1775 /*
1776 * Set Negotiated link rate.
1777 */
1778 switch (phy_info->negotiated_link_rate) {
1779 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001780 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001781 break;
1782 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001783 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001784 break;
1785 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001786 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001787 break;
1788 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001789 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001790 break;
1791 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1792 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1793 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001794 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001795 break;
1796 }
1797
1798 /*
1799 * Set Max hardware link rate.
1800 */
1801 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1802 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001803 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001804 break;
1805 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001806 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001807 break;
1808 default:
1809 break;
1810 }
1811
1812 /*
1813 * Set Max programmed link rate.
1814 */
1815 switch (phy_info->programmed_link_rate &
1816 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1817 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001818 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001819 break;
1820 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001821 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001822 break;
1823 default:
1824 break;
1825 }
1826
1827 /*
1828 * Set Min hardware link rate.
1829 */
1830 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1831 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001832 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001833 break;
1834 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001835 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001836 break;
1837 default:
1838 break;
1839 }
1840
1841 /*
1842 * Set Min programmed link rate.
1843 */
1844 switch (phy_info->programmed_link_rate &
1845 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1846 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001847 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848 break;
1849 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001850 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001851 break;
1852 default:
1853 break;
1854 }
1855
Moore, Erice6b2d762006-03-14 09:14:24 -07001856 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001857
Moore, Erice6b2d762006-03-14 09:14:24 -07001858 error = sas_phy_add(phy);
1859 if (error) {
1860 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001861 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001862 }
1863 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001864 }
1865
Eric Moore547f9a22006-06-27 14:42:12 -06001866 if (!phy_info->attached.handle ||
1867 !phy_info->port_details)
1868 goto out;
1869
1870 port = mptsas_get_port(phy_info);
1871 ioc = phy_to_ioc(phy_info->phy);
1872
1873 if (phy_info->sas_port_add_phy) {
1874
1875 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001876 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001877 if (!port) {
1878 error = -ENOMEM;
1879 goto out;
1880 }
1881 error = sas_port_add(port);
1882 if (error) {
1883 dfailprintk((MYIOC_s_ERR_FMT
1884 "%s: exit at line=%d\n", ioc->name,
1885 __FUNCTION__, __LINE__));
1886 goto out;
1887 }
1888 mptsas_set_port(phy_info, port);
Eric Mooredc22f162006-07-06 11:23:14 -06001889 dsaswideprintk((KERN_DEBUG
1890 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
1891 port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001892 }
1893 dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
1894 phy_info->phy_id));
1895 sas_port_add_phy(port, phy_info->phy);
1896 phy_info->sas_port_add_phy = 0;
1897 }
1898
1899 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001900
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001901 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05001902 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06001903 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001904
James Bottomley2686de22006-06-30 12:54:02 -05001905 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07001906 /*
1907 * Let the hotplug_work thread handle processing
1908 * the adding/removing of devices that occur
1909 * after start of day.
1910 */
1911 if (ioc->sas_discovery_runtime &&
1912 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06001913 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001914
James Bottomleyf013db32006-03-18 14:54:36 -06001915 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05001916 if (scsi_is_host_device(parent)) {
1917 struct mptsas_portinfo *port_info;
1918 int i;
1919
1920 mutex_lock(&ioc->sas_topology_mutex);
1921 port_info = mptsas_find_portinfo_by_handle(ioc,
1922 ioc->handle);
1923 mutex_unlock(&ioc->sas_topology_mutex);
1924
1925 for (i = 0; i < port_info->num_phys; i++)
1926 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001927 identify.sas_address) {
1928 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001929 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001930 }
James Bottomley2686de22006-06-30 12:54:02 -05001931
1932 } else if (scsi_is_sas_rphy(parent)) {
1933 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
1934 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04001935 parent_rphy->identify.sas_address) {
1936 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05001937 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04001938 }
James Bottomley2686de22006-06-30 12:54:02 -05001939 }
1940
James Bottomleyf013db32006-03-18 14:54:36 -06001941 switch (identify.device_type) {
1942 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001943 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06001944 break;
1945 case SAS_EDGE_EXPANDER_DEVICE:
1946 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06001947 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06001948 break;
1949 default:
1950 rphy = NULL;
1951 break;
1952 }
Eric Moore547f9a22006-06-27 14:42:12 -06001953 if (!rphy) {
1954 dfailprintk((MYIOC_s_ERR_FMT
1955 "%s: exit at line=%d\n", ioc->name,
1956 __FUNCTION__, __LINE__));
1957 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001958 }
1959
Eric Moore547f9a22006-06-27 14:42:12 -06001960 rphy->identify = identify;
1961 error = sas_rphy_add(rphy);
1962 if (error) {
1963 dfailprintk((MYIOC_s_ERR_FMT
1964 "%s: exit at line=%d\n", ioc->name,
1965 __FUNCTION__, __LINE__));
1966 sas_rphy_free(rphy);
1967 goto out;
1968 }
1969 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001970 }
1971
Eric Moore547f9a22006-06-27 14:42:12 -06001972 out:
1973 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001974}
1975
1976static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001977mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001978{
Moore, Erice6b2d762006-03-14 09:14:24 -07001979 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001980 int error = -ENOMEM, i;
1981
Moore, Erice6b2d762006-03-14 09:14:24 -07001982 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1983 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001984 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001985
Moore, Erice6b2d762006-03-14 09:14:24 -07001986 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001987 if (error)
1988 goto out_free_port_info;
1989
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001990 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07001991 ioc->handle = hba->phy_info[0].handle;
1992 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001993 if (!port_info) {
1994 port_info = hba;
1995 list_add_tail(&port_info->list, &ioc->sas_topology);
1996 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07001997 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07001998 port_info->phy_info[i].negotiated_link_rate =
1999 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002000 port_info->phy_info[i].handle =
2001 hba->phy_info[i].handle;
2002 port_info->phy_info[i].port_id =
2003 hba->phy_info[i].port_id;
2004 }
Eric Moore547f9a22006-06-27 14:42:12 -06002005 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002006 kfree(hba);
2007 hba = NULL;
2008 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002009 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002010 for (i = 0; i < port_info->num_phys; i++) {
2011 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2012 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2013 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2014
2015 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002016 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2017 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2018 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002019 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002020 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002021 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002022 mptsas_sas_device_pg0(ioc,
2023 &port_info->phy_info[i].attached,
2024 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2025 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2026 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002027 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002028
Eric Moore547f9a22006-06-27 14:42:12 -06002029 mptsas_setup_wide_ports(ioc, port_info);
2030
2031 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002032 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002033 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002034
2035 return 0;
2036
2037 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002038 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002039 out:
2040 return error;
2041}
2042
2043static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002044mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002045{
Moore, Erice6b2d762006-03-14 09:14:24 -07002046 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002047 struct device *parent;
2048 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002049 int error = -ENOMEM, i, j;
2050
Moore, Erice6b2d762006-03-14 09:14:24 -07002051 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2052 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002053 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002054
Moore, Erice6b2d762006-03-14 09:14:24 -07002055 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002056 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2057 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002058 if (error)
2059 goto out_free_port_info;
2060
Eric Moore2ecce492007-01-29 09:47:08 -07002061 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002062
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002063 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002064 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2065 if (!port_info) {
2066 port_info = ex;
2067 list_add_tail(&port_info->list, &ioc->sas_topology);
2068 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002069 for (i = 0; i < ex->num_phys; i++) {
2070 port_info->phy_info[i].handle =
2071 ex->phy_info[i].handle;
2072 port_info->phy_info[i].port_id =
2073 ex->phy_info[i].port_id;
2074 }
Eric Moore547f9a22006-06-27 14:42:12 -06002075 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002076 kfree(ex);
2077 ex = NULL;
2078 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002079 mutex_unlock(&ioc->sas_topology_mutex);
2080
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002081 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002082 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2083 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2084 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2085
2086 if (port_info->phy_info[i].identify.handle) {
2087 mptsas_sas_device_pg0(ioc,
2088 &port_info->phy_info[i].identify,
2089 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2090 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2091 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002092 port_info->phy_info[i].identify.phy_id =
2093 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002094 }
2095
2096 if (port_info->phy_info[i].attached.handle) {
2097 mptsas_sas_device_pg0(ioc,
2098 &port_info->phy_info[i].attached,
2099 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2100 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2101 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002102 port_info->phy_info[i].attached.phy_id =
2103 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002104 }
Eric Moore547f9a22006-06-27 14:42:12 -06002105 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002106
Eric Moore547f9a22006-06-27 14:42:12 -06002107 parent = &ioc->sh->shost_gendev;
2108 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002109 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002110 list_for_each_entry(p, &ioc->sas_topology, list) {
2111 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002112 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002113 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002114 continue;
2115 rphy = mptsas_get_rphy(&p->phy_info[j]);
2116 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002117 }
2118 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002119 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002120 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002121
Eric Moore547f9a22006-06-27 14:42:12 -06002122 mptsas_setup_wide_ports(ioc, port_info);
2123
2124 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002125 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002126 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002127
2128 return 0;
2129
2130 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002131 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002132 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002133 kfree(ex);
2134 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002135 out:
2136 return error;
2137}
2138
Moore, Erice6b2d762006-03-14 09:14:24 -07002139/*
2140 * mptsas_delete_expander_phys
2141 *
2142 *
2143 * This will traverse topology, and remove expanders
2144 * that are no longer present
2145 */
2146static void
2147mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2148{
2149 struct mptsas_portinfo buffer;
2150 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002151 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002152 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002153 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002154 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002155
2156 mutex_lock(&ioc->sas_topology_mutex);
2157 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2158
2159 if (port_info->phy_info &&
2160 (!(port_info->phy_info[0].identify.device_info &
2161 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2162 continue;
2163
2164 if (mptsas_sas_expander_pg0(ioc, &buffer,
2165 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002166 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2167 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002168
2169 /*
2170 * Obtain the port_info instance to the parent port
2171 */
2172 parent = mptsas_find_portinfo_by_handle(ioc,
2173 port_info->phy_info[0].identify.handle_parent);
2174
2175 if (!parent)
2176 goto next_port;
2177
Eric Moore547f9a22006-06-27 14:42:12 -06002178 expander_sas_address =
2179 port_info->phy_info[0].identify.sas_address;
2180
Moore, Erice6b2d762006-03-14 09:14:24 -07002181 /*
2182 * Delete rphys in the parent that point
2183 * to this expander. The transport layer will
2184 * cleanup all the children.
2185 */
Eric Moore547f9a22006-06-27 14:42:12 -06002186 phy_info = parent->phy_info;
2187 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2188 port = mptsas_get_port(phy_info);
2189 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002190 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002191 if (phy_info->attached.sas_address !=
2192 expander_sas_address)
2193 continue;
2194#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002195 dev_printk(KERN_DEBUG, &port->dev,
2196 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002197#endif
2198 sas_port_delete(port);
2199 mptsas_port_delete(phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002200 }
2201 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002202
2203 phy_info = port_info->phy_info;
2204 for (i = 0; i < port_info->num_phys; i++, phy_info++)
2205 mptsas_port_delete(phy_info->port_details);
2206
Moore, Erice6b2d762006-03-14 09:14:24 -07002207 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002208 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002209 kfree(port_info);
2210 }
2211 /*
2212 * Free this memory allocated from inside
2213 * mptsas_sas_expander_pg0
2214 */
Eric Moore547f9a22006-06-27 14:42:12 -06002215 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002216 }
2217 mutex_unlock(&ioc->sas_topology_mutex);
2218}
2219
2220/*
2221 * Start of day discovery
2222 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002223static void
2224mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2225{
2226 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002227 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002228
Moore, Erice6b2d762006-03-14 09:14:24 -07002229 mutex_lock(&ioc->sas_discovery_mutex);
2230 mptsas_probe_hba_phys(ioc);
2231 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002232 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002233 /*
2234 Reporting RAID volumes.
2235 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002236 if (!ioc->ir_firmware)
2237 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002238 if (!ioc->raid_data.pIocPg2)
2239 goto out;
2240 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2241 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002242 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002243 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002244 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2245 }
2246 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002247 mutex_unlock(&ioc->sas_discovery_mutex);
2248}
2249
2250/*
2251 * Work queue thread to handle Runtime discovery
2252 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002253 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002254 */
2255static void
Eric Moore547f9a22006-06-27 14:42:12 -06002256__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002257{
Moore, Erice6b2d762006-03-14 09:14:24 -07002258 u32 handle = 0xFFFF;
2259
Moore, Erice6b2d762006-03-14 09:14:24 -07002260 ioc->sas_discovery_runtime=1;
2261 mptsas_delete_expander_phys(ioc);
2262 mptsas_probe_hba_phys(ioc);
2263 while (!mptsas_probe_expander_phys(ioc, &handle))
2264 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002265 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002266}
2267
2268/*
2269 * Work queue thread to handle Runtime discovery
2270 * Mere purpose is the hot add/delete of expanders
2271 *(Mutex LOCKED)
2272 */
2273static void
David Howellsc4028952006-11-22 14:57:56 +00002274mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002275{
David Howellsc4028952006-11-22 14:57:56 +00002276 struct mptsas_discovery_event *ev =
2277 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002278 MPT_ADAPTER *ioc = ev->ioc;
2279
2280 mutex_lock(&ioc->sas_discovery_mutex);
2281 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002282 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002283 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002284}
2285
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002286static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002287mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002288{
2289 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002290 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002291 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002292
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002293 mutex_lock(&ioc->sas_topology_mutex);
2294 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2295 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002296 if (!mptsas_is_end_device(
2297 &port_info->phy_info[i].attached))
2298 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002299 if (port_info->phy_info[i].attached.sas_address
2300 != sas_address)
2301 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002302 phy_info = &port_info->phy_info[i];
2303 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002304 }
2305 }
2306 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002307 return phy_info;
2308}
2309
2310static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002311mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002312{
2313 struct mptsas_portinfo *port_info;
2314 struct mptsas_phyinfo *phy_info = NULL;
2315 int i;
2316
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002317 mutex_lock(&ioc->sas_topology_mutex);
2318 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002319 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002320 if (!mptsas_is_end_device(
2321 &port_info->phy_info[i].attached))
2322 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002323 if (port_info->phy_info[i].attached.id != id)
2324 continue;
2325 if (port_info->phy_info[i].attached.channel != channel)
2326 continue;
2327 phy_info = &port_info->phy_info[i];
2328 break;
2329 }
2330 }
2331 mutex_unlock(&ioc->sas_topology_mutex);
2332 return phy_info;
2333}
2334
2335static struct mptsas_phyinfo *
2336mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2337{
2338 struct mptsas_portinfo *port_info;
2339 struct mptsas_phyinfo *phy_info = NULL;
2340 int i;
2341
2342 mutex_lock(&ioc->sas_topology_mutex);
2343 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2344 for (i = 0; i < port_info->num_phys; i++) {
2345 if (!mptsas_is_end_device(
2346 &port_info->phy_info[i].attached))
2347 continue;
2348 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2349 continue;
2350 if (port_info->phy_info[i].attached.phys_disk_num != id)
2351 continue;
2352 if (port_info->phy_info[i].attached.channel != channel)
2353 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002354 phy_info = &port_info->phy_info[i];
2355 break;
2356 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002357 }
2358 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002359 return phy_info;
2360}
2361
Moore, Eric4b766472006-03-14 09:14:12 -07002362/*
2363 * Work queue thread to clear the persitency table
2364 */
2365static void
David Howellsc4028952006-11-22 14:57:56 +00002366mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002367{
David Howellsc4028952006-11-22 14:57:56 +00002368 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002369
2370 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2371}
2372
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002373static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002374mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2375{
Eric Mooref99be432007-01-04 20:46:54 -07002376 int rc;
2377
Moore, Ericf44e5462006-03-14 09:14:21 -07002378 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002379 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002380}
2381
2382static void
2383mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2384{
2385 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2386 mptsas_reprobe_lun);
2387}
2388
Eric Mooreb506ade2007-01-29 09:45:37 -07002389static void
2390mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2391{
2392 CONFIGPARMS cfg;
2393 ConfigPageHeader_t hdr;
2394 dma_addr_t dma_handle;
2395 pRaidVolumePage0_t buffer = NULL;
2396 RaidPhysDiskPage0_t phys_disk;
2397 int i;
2398 struct mptsas_hotplug_event *ev;
2399
2400 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2401 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2402 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2403 cfg.pageAddr = (channel << 8) + id;
2404 cfg.cfghdr.hdr = &hdr;
2405 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2406
2407 if (mpt_config(ioc, &cfg) != 0)
2408 goto out;
2409
2410 if (!hdr.PageLength)
2411 goto out;
2412
2413 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2414 &dma_handle);
2415
2416 if (!buffer)
2417 goto out;
2418
2419 cfg.physAddr = dma_handle;
2420 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2421
2422 if (mpt_config(ioc, &cfg) != 0)
2423 goto out;
2424
2425 if (!(buffer->VolumeStatus.Flags &
2426 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2427 goto out;
2428
2429 if (!buffer->NumPhysDisks)
2430 goto out;
2431
2432 for (i = 0; i < buffer->NumPhysDisks; i++) {
2433
2434 if (mpt_raid_phys_disk_pg0(ioc,
2435 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2436 continue;
2437
2438 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2439 if (!ev) {
2440 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2441 goto out;
2442 }
2443
2444 INIT_WORK(&ev->work, mptsas_hotplug_work);
2445 ev->ioc = ioc;
2446 ev->id = phys_disk.PhysDiskID;
2447 ev->channel = phys_disk.PhysDiskBus;
2448 ev->phys_disk_num_valid = 1;
2449 ev->phys_disk_num = phys_disk.PhysDiskNum;
2450 ev->event_type = MPTSAS_ADD_DEVICE;
2451 schedule_work(&ev->work);
2452 }
2453
2454 out:
2455 if (buffer)
2456 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2457 dma_handle);
2458}
Moore, Erice6b2d762006-03-14 09:14:24 -07002459/*
2460 * Work queue thread to handle SAS hotplug events
2461 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002462static void
David Howellsc4028952006-11-22 14:57:56 +00002463mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002464{
David Howellsc4028952006-11-22 14:57:56 +00002465 struct mptsas_hotplug_event *ev =
2466 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002467
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002468 MPT_ADAPTER *ioc = ev->ioc;
2469 struct mptsas_phyinfo *phy_info;
2470 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002471 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002472 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002473 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002474 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002475 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002476 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002477 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002478 VirtDevice *vdevice;
2479
Moore, Erice6b2d762006-03-14 09:14:24 -07002480 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002481 switch (ev->event_type) {
2482 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002483
Eric Mooreb506ade2007-01-29 09:45:37 -07002484 phy_info = NULL;
2485 if (ev->phys_disk_num_valid) {
2486 if (ev->hidden_raid_component){
2487 if (mptsas_sas_device_pg0(ioc, &sas_device,
2488 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2489 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2490 (ev->channel << 8) + ev->id)) {
2491 dfailprintk((MYIOC_s_ERR_FMT
2492 "%s: exit at line=%d\n", ioc->name,
2493 __FUNCTION__, __LINE__));
2494 break;
2495 }
2496 phy_info = mptsas_find_phyinfo_by_sas_address(
2497 ioc, sas_device.sas_address);
2498 }else
2499 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2500 ioc, ev->channel, ev->phys_disk_num);
2501 }
2502
2503 if (!phy_info)
2504 phy_info = mptsas_find_phyinfo_by_target(ioc,
2505 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002506
Moore, Ericf44e5462006-03-14 09:14:21 -07002507 /*
2508 * Sanity checks, for non-existing phys and remote rphys.
2509 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002510 if (!phy_info){
2511 dfailprintk((MYIOC_s_ERR_FMT
2512 "%s: exit at line=%d\n", ioc->name,
2513 __FUNCTION__, __LINE__));
2514 break;
2515 }
2516 if (!phy_info->port_details) {
Eric Moore547f9a22006-06-27 14:42:12 -06002517 dfailprintk((MYIOC_s_ERR_FMT
2518 "%s: exit at line=%d\n", ioc->name,
2519 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002520 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002521 }
2522 rphy = mptsas_get_rphy(phy_info);
2523 if (!rphy) {
2524 dfailprintk((MYIOC_s_ERR_FMT
2525 "%s: exit at line=%d\n", ioc->name,
2526 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002527 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002528 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002529
Eric Moore547f9a22006-06-27 14:42:12 -06002530 port = mptsas_get_port(phy_info);
2531 if (!port) {
2532 dfailprintk((MYIOC_s_ERR_FMT
2533 "%s: exit at line=%d\n", ioc->name,
2534 __FUNCTION__, __LINE__));
2535 break;
2536 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002537
Eric Moore547f9a22006-06-27 14:42:12 -06002538 starget = mptsas_get_starget(phy_info);
2539 if (starget) {
2540 vtarget = starget->hostdata;
2541
2542 if (!vtarget) {
2543 dfailprintk((MYIOC_s_ERR_FMT
2544 "%s: exit at line=%d\n", ioc->name,
2545 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002546 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002547 }
2548
Moore, Ericf44e5462006-03-14 09:14:21 -07002549 /*
2550 * Handling RAID components
2551 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002552 if (ev->phys_disk_num_valid &&
2553 ev->hidden_raid_component) {
2554 printk(MYIOC_s_INFO_FMT
2555 "RAID Hidding: channel=%d, id=%d, "
2556 "physdsk %d \n", ioc->name, ev->channel,
2557 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002558 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002559 vtarget->tflags |=
2560 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002561 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002562 phy_info->attached.phys_disk_num =
2563 ev->phys_disk_num;
2564 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002565 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002566 }
2567
Eric Mooreb506ade2007-01-29 09:45:37 -07002568 if (phy_info->attached.device_info &
2569 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002570 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002571 if (phy_info->attached.device_info &
2572 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002573 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002574 if (phy_info->attached.device_info &
2575 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002576 ds = "sata";
2577
2578 printk(MYIOC_s_INFO_FMT
2579 "removing %s device, channel %d, id %d, phy %d\n",
2580 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore547f9a22006-06-27 14:42:12 -06002581#ifdef MPT_DEBUG_SAS_WIDE
Eric Mooredc22f162006-07-06 11:23:14 -06002582 dev_printk(KERN_DEBUG, &port->dev,
2583 "delete port (%d)\n", port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002584#endif
2585 sas_port_delete(port);
2586 mptsas_port_delete(phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002587 break;
2588 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002589
Moore, Ericbd23e942006-04-17 12:43:04 -06002590 if (ev->phys_disk_num_valid)
2591 mpt_findImVolumes(ioc);
2592
Moore, Ericc73787ee2006-01-26 16:20:06 -07002593 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002594 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002595 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002596 if (mptsas_sas_device_pg0(ioc, &sas_device,
2597 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002598 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2599 (ev->channel << 8) + ev->id)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002600 dfailprintk((MYIOC_s_ERR_FMT
2601 "%s: exit at line=%d\n", ioc->name,
2602 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002603 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002604 }
2605
Eric Moore547f9a22006-06-27 14:42:12 -06002606 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002607
Eric Moore547f9a22006-06-27 14:42:12 -06002608 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2609 sas_device.sas_address);
2610
2611 if (!phy_info || !phy_info->port_details) {
2612 dfailprintk((MYIOC_s_ERR_FMT
2613 "%s: exit at line=%d\n", ioc->name,
2614 __FUNCTION__, __LINE__));
2615 break;
2616 }
2617
2618 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002619 if (starget && (!ev->hidden_raid_component)){
2620
Eric Moore547f9a22006-06-27 14:42:12 -06002621 vtarget = starget->hostdata;
2622
2623 if (!vtarget) {
2624 dfailprintk((MYIOC_s_ERR_FMT
2625 "%s: exit at line=%d\n", ioc->name,
2626 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002627 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002628 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002629 /*
2630 * Handling RAID components
2631 */
2632 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002633 printk(MYIOC_s_INFO_FMT
2634 "RAID Exposing: channel=%d, id=%d, "
2635 "physdsk %d \n", ioc->name, ev->channel,
2636 ev->id, ev->phys_disk_num);
2637 vtarget->tflags &=
2638 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002639 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002640 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002641 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002642 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002643 break;
2644 }
2645
Eric Moore547f9a22006-06-27 14:42:12 -06002646 if (mptsas_get_rphy(phy_info)) {
2647 dfailprintk((MYIOC_s_ERR_FMT
2648 "%s: exit at line=%d\n", ioc->name,
2649 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002650 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002651 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002652 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002653
Eric Moore547f9a22006-06-27 14:42:12 -06002654 port = mptsas_get_port(phy_info);
2655 if (!port) {
2656 dfailprintk((MYIOC_s_ERR_FMT
2657 "%s: exit at line=%d\n", ioc->name,
2658 __FUNCTION__, __LINE__));
2659 break;
2660 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002661 memcpy(&phy_info->attached, &sas_device,
2662 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002663
Eric Mooreb506ade2007-01-29 09:45:37 -07002664 if (phy_info->attached.device_info &
2665 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002666 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002667 if (phy_info->attached.device_info &
2668 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002669 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002670 if (phy_info->attached.device_info &
2671 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002672 ds = "sata";
2673
2674 printk(MYIOC_s_INFO_FMT
2675 "attaching %s device, channel %d, id %d, phy %d\n",
2676 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2677
James Bottomleyf013db32006-03-18 14:54:36 -06002678 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002679 rphy = sas_end_device_alloc(port);
2680 if (!rphy) {
2681 dfailprintk((MYIOC_s_ERR_FMT
2682 "%s: exit at line=%d\n", ioc->name,
2683 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002684 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002685 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002686
James Bottomleyf013db32006-03-18 14:54:36 -06002687 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002688 if (sas_rphy_add(rphy)) {
Eric Moore547f9a22006-06-27 14:42:12 -06002689 dfailprintk((MYIOC_s_ERR_FMT
2690 "%s: exit at line=%d\n", ioc->name,
2691 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002692 sas_rphy_free(rphy);
2693 break;
2694 }
Eric Moore547f9a22006-06-27 14:42:12 -06002695 mptsas_set_rphy(phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002696 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002697 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002698 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2699 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002700 if (sdev) {
2701 scsi_device_put(sdev);
2702 break;
2703 }
2704 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002705 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002706 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2707 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002708 mpt_findImVolumes(ioc);
2709 break;
2710 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002711 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002712 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002713 if (!sdev)
2714 break;
2715 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002716 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002717 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002718 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002719 scsi_remove_device(sdev);
2720 scsi_device_put(sdev);
2721 mpt_findImVolumes(ioc);
2722 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002723 case MPTSAS_ADD_INACTIVE_VOLUME:
2724 mptsas_adding_inactive_raid_components(ioc,
2725 ev->channel, ev->id);
2726 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002727 case MPTSAS_IGNORE_EVENT:
2728 default:
2729 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002730 }
2731
Moore, Erice6b2d762006-03-14 09:14:24 -07002732 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002733 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002734}
2735
2736static void
Eric Moore547f9a22006-06-27 14:42:12 -06002737mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002738 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2739{
2740 struct mptsas_hotplug_event *ev;
2741 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2742 __le64 sas_address;
2743
2744 if ((device_info &
2745 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2746 MPI_SAS_DEVICE_INFO_STP_TARGET |
2747 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2748 return;
2749
Moore, Eric4b766472006-03-14 09:14:12 -07002750 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002751 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002752
2753 mptsas_target_reset_queue(ioc, sas_event_data);
2754 break;
2755
2756 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002757 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002758 if (!ev) {
2759 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2760 break;
2761 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002762
David Howellsc4028952006-11-22 14:57:56 +00002763 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002764 ev->ioc = ioc;
2765 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2766 ev->parent_handle =
2767 le16_to_cpu(sas_event_data->ParentDevHandle);
2768 ev->channel = sas_event_data->Bus;
2769 ev->id = sas_event_data->TargetID;
2770 ev->phy_id = sas_event_data->PhyNum;
2771 memcpy(&sas_address, &sas_event_data->SASAddress,
2772 sizeof(__le64));
2773 ev->sas_address = le64_to_cpu(sas_address);
2774 ev->device_info = device_info;
2775
2776 if (sas_event_data->ReasonCode &
2777 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2778 ev->event_type = MPTSAS_ADD_DEVICE;
2779 else
2780 ev->event_type = MPTSAS_DEL_DEVICE;
2781 schedule_work(&ev->work);
2782 break;
2783 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2784 /*
2785 * Persistent table is full.
2786 */
Eric Moore547f9a22006-06-27 14:42:12 -06002787 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002788 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002789 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002790 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002791 /*
2792 * TODO, handle other events
2793 */
Moore, Eric4b766472006-03-14 09:14:12 -07002794 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002795 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002796 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002797 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2798 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2799 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2800 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002801 default:
2802 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002803 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002804}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002805static void
Eric Moore547f9a22006-06-27 14:42:12 -06002806mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002807 EVENT_DATA_RAID *raid_event_data)
2808{
2809 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002810 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2811 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002812
2813 if (ioc->bus_type != SAS)
2814 return;
2815
Eric Moore547f9a22006-06-27 14:42:12 -06002816 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002817 if (!ev) {
2818 printk(KERN_WARNING "mptsas: lost hotplug event\n");
2819 return;
2820 }
2821
David Howellsc4028952006-11-22 14:57:56 +00002822 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002823 ev->ioc = ioc;
2824 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002825 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002826 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002827
2828 switch (raid_event_data->ReasonCode) {
2829 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002830 ev->phys_disk_num_valid = 1;
2831 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002832 ev->event_type = MPTSAS_ADD_DEVICE;
2833 break;
2834 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002835 ev->phys_disk_num_valid = 1;
2836 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002837 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002838 ev->event_type = MPTSAS_DEL_DEVICE;
2839 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002840 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2841 switch (state) {
2842 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002843 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002844 ev->phys_disk_num_valid = 1;
2845 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002846 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002847 ev->event_type = MPTSAS_ADD_DEVICE;
2848 break;
2849 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002850 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2851 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2852 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002853 ev->phys_disk_num_valid = 1;
2854 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002855 ev->event_type = MPTSAS_DEL_DEVICE;
2856 break;
2857 default:
2858 break;
2859 }
2860 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002861 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2862 ev->event_type = MPTSAS_DEL_RAID;
2863 break;
2864 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2865 ev->event_type = MPTSAS_ADD_RAID;
2866 break;
2867 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002868 switch (state) {
2869 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2870 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2871 ev->event_type = MPTSAS_DEL_RAID;
2872 break;
2873 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2874 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2875 ev->event_type = MPTSAS_ADD_RAID;
2876 break;
2877 default:
2878 break;
2879 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002880 break;
2881 default:
2882 break;
2883 }
2884 schedule_work(&ev->work);
2885}
2886
Moore, Erice6b2d762006-03-14 09:14:24 -07002887static void
Eric Moore547f9a22006-06-27 14:42:12 -06002888mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002889 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2890{
2891 struct mptsas_discovery_event *ev;
2892
2893 /*
2894 * DiscoveryStatus
2895 *
2896 * This flag will be non-zero when firmware
2897 * kicks off discovery, and return to zero
2898 * once its completed.
2899 */
2900 if (discovery_data->DiscoveryStatus)
2901 return;
2902
Eric Moore547f9a22006-06-27 14:42:12 -06002903 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07002904 if (!ev)
2905 return;
David Howellsc4028952006-11-22 14:57:56 +00002906 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07002907 ev->ioc = ioc;
2908 schedule_work(&ev->work);
2909};
2910
Eric Mooreb506ade2007-01-29 09:45:37 -07002911/*
2912 * mptsas_send_ir2_event - handle exposing hidden disk when
2913 * an inactive raid volume is added
2914 *
2915 * @ioc: Pointer to MPT_ADAPTER structure
2916 * @ir2_data
2917 *
2918 */
2919static void
2920mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
2921{
2922 struct mptsas_hotplug_event *ev;
2923
2924 if (ir2_data->ReasonCode !=
2925 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
2926 return;
2927
2928 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2929 if (!ev)
2930 return;
2931
2932 INIT_WORK(&ev->work, mptsas_hotplug_work);
2933 ev->ioc = ioc;
2934 ev->id = ir2_data->TargetID;
2935 ev->channel = ir2_data->Bus;
2936 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
2937
2938 schedule_work(&ev->work);
2939};
Moore, Erice6b2d762006-03-14 09:14:24 -07002940
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002941static int
2942mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2943{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002944 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002945 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2946
2947 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002948 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002949
Moore, Erice6b2d762006-03-14 09:14:24 -07002950 /*
2951 * sas_discovery_ignore_events
2952 *
2953 * This flag is to prevent anymore processing of
2954 * sas events once mptsas_remove function is called.
2955 */
2956 if (ioc->sas_discovery_ignore_events) {
2957 rc = mptscsih_event_process(ioc, reply);
2958 goto out;
2959 }
2960
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002961 switch (event) {
2962 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06002963 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002964 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002965 break;
2966 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06002967 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002968 (EVENT_DATA_RAID *)reply->Data);
2969 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002970 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06002971 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002972 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002973 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07002974 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002975 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06002976 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002977 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2978 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002979 case MPI_EVENT_IR2:
2980 mptsas_send_ir2_event(ioc,
2981 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
2982 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002983 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002984 rc = mptscsih_event_process(ioc, reply);
2985 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002986 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002987 out:
2988
2989 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002990}
2991
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002992static int
2993mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2994{
2995 struct Scsi_Host *sh;
2996 MPT_SCSI_HOST *hd;
2997 MPT_ADAPTER *ioc;
2998 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002999 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003000 int numSGE = 0;
3001 int scale;
3002 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003003 int error=0;
3004 int r;
3005
3006 r = mpt_attach(pdev,id);
3007 if (r)
3008 return r;
3009
3010 ioc = pci_get_drvdata(pdev);
3011 ioc->DoneCtx = mptsasDoneCtx;
3012 ioc->TaskCtx = mptsasTaskCtx;
3013 ioc->InternalCtx = mptsasInternalCtx;
3014
3015 /* Added sanity check on readiness of the MPT adapter.
3016 */
3017 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3018 printk(MYIOC_s_WARN_FMT
3019 "Skipping because it's not operational!\n",
3020 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003021 error = -ENODEV;
3022 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003023 }
3024
3025 if (!ioc->active) {
3026 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3027 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003028 error = -ENODEV;
3029 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003030 }
3031
3032 /* Sanity check - ensure at least 1 port is INITIATOR capable
3033 */
3034 ioc_cap = 0;
3035 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3036 if (ioc->pfacts[ii].ProtocolFlags &
3037 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3038 ioc_cap++;
3039 }
3040
3041 if (!ioc_cap) {
3042 printk(MYIOC_s_WARN_FMT
3043 "Skipping ioc=%p because SCSI Initiator mode "
3044 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003045 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003046 }
3047
3048 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3049 if (!sh) {
3050 printk(MYIOC_s_WARN_FMT
3051 "Unable to register controller with SCSI subsystem\n",
3052 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003053 error = -1;
3054 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003055 }
3056
3057 spin_lock_irqsave(&ioc->FreeQlock, flags);
3058
3059 /* Attach the SCSI Host to the IOC structure
3060 */
3061 ioc->sh = sh;
3062
3063 sh->io_port = 0;
3064 sh->n_io_port = 0;
3065 sh->irq = 0;
3066
3067 /* set 16 byte cdb's */
3068 sh->max_cmd_len = 16;
3069
Eric Moore793955f2007-01-29 09:42:20 -07003070 sh->max_id = ioc->pfacts[0].PortSCSIID;
3071 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003072
3073 sh->transportt = mptsas_transport_template;
3074
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003075 sh->this_id = ioc->pfacts[0].PortSCSIID;
3076
3077 /* Required entry.
3078 */
3079 sh->unique_id = ioc->id;
3080
3081 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003082 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003083 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003084 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003085 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003086
3087 /* Verify that we won't exceed the maximum
3088 * number of chain buffers
3089 * We can optimize: ZZ = req_sz/sizeof(SGE)
3090 * For 32bit SGE's:
3091 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3092 * + (req_sz - 64)/sizeof(SGE)
3093 * A slightly different algorithm is required for
3094 * 64bit SGEs.
3095 */
3096 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3097 if (sizeof(dma_addr_t) == sizeof(u64)) {
3098 numSGE = (scale - 1) *
3099 (ioc->facts.MaxChainDepth-1) + scale +
3100 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3101 sizeof(u32));
3102 } else {
3103 numSGE = 1 + (scale - 1) *
3104 (ioc->facts.MaxChainDepth-1) + scale +
3105 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3106 sizeof(u32));
3107 }
3108
3109 if (numSGE < sh->sg_tablesize) {
3110 /* Reset this value */
3111 dprintk((MYIOC_s_INFO_FMT
3112 "Resetting sg_tablesize to %d from %d\n",
3113 ioc->name, numSGE, sh->sg_tablesize));
3114 sh->sg_tablesize = numSGE;
3115 }
3116
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003117 hd = (MPT_SCSI_HOST *) sh->hostdata;
3118 hd->ioc = ioc;
3119
3120 /* SCSI needs scsi_cmnd lookup table!
3121 * (with size equal to req_depth*PtrSz!)
3122 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003123 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3124 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003125 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003126 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003127 }
3128
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003129 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
3130 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003131
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003132 /* Clear the TM flags
3133 */
3134 hd->tmPending = 0;
3135 hd->tmState = TM_STATE_NONE;
3136 hd->resetPending = 0;
3137 hd->abortSCpnt = NULL;
3138
3139 /* Clear the pointer used to store
3140 * single-threaded commands, i.e., those
3141 * issued during a bus scan, dv and
3142 * configuration pages.
3143 */
3144 hd->cmdPtr = NULL;
3145
3146 /* Initialize this SCSI Hosts' timers
3147 * To use, set the timer expires field
3148 * and add_timer
3149 */
3150 init_timer(&hd->timer);
3151 hd->timer.data = (unsigned long) hd;
3152 hd->timer.function = mptscsih_timer_expired;
3153
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003154 ioc->sas_data.ptClear = mpt_pt_clear;
3155
Eric Mooredf9e0622007-01-29 09:46:21 -07003156 init_waitqueue_head(&hd->scandv_waitq);
3157 hd->scandv_wait_done = 0;
3158 hd->last_queue_full = 0;
3159 INIT_LIST_HEAD(&hd->target_reset_list);
3160 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3161
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003162 if (ioc->sas_data.ptClear==1) {
3163 mptbase_sas_persist_operation(
3164 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3165 }
3166
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003167 error = scsi_add_host(sh, &ioc->pcidev->dev);
3168 if (error) {
3169 dprintk((KERN_ERR MYNAM
3170 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003171 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003172 }
3173
3174 mptsas_scan_sas_topology(ioc);
3175
3176 return 0;
3177
Eric Moore547f9a22006-06-27 14:42:12 -06003178 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003179
3180 mptscsih_remove(pdev);
3181 return error;
3182}
3183
3184static void __devexit mptsas_remove(struct pci_dev *pdev)
3185{
3186 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3187 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003188 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003189
Eric Mooreb506ade2007-01-29 09:45:37 -07003190 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003191 sas_remove_host(ioc->sh);
3192
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003193 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003194 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3195 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003196 for (i = 0 ; i < p->num_phys ; i++)
3197 mptsas_port_delete(p->phy_info[i].port_details);
3198 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003199 kfree(p);
3200 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003201 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003202
3203 mptscsih_remove(pdev);
3204}
3205
3206static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003207 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003208 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003209 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003210 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003211 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003212 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003213 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003214 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003215 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003216 PCI_ANY_ID, PCI_ANY_ID },
3217 {0} /* Terminating entry */
3218};
3219MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3220
3221
3222static struct pci_driver mptsas_driver = {
3223 .name = "mptsas",
3224 .id_table = mptsas_pci_table,
3225 .probe = mptsas_probe,
3226 .remove = __devexit_p(mptsas_remove),
3227 .shutdown = mptscsih_shutdown,
3228#ifdef CONFIG_PM
3229 .suspend = mptscsih_suspend,
3230 .resume = mptscsih_resume,
3231#endif
3232};
3233
3234static int __init
3235mptsas_init(void)
3236{
3237 show_mptmod_ver(my_NAME, my_VERSION);
3238
3239 mptsas_transport_template =
3240 sas_attach_transport(&mptsas_transport_functions);
3241 if (!mptsas_transport_template)
3242 return -ENODEV;
3243
3244 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003245 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003246 mptsasInternalCtx =
3247 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003248 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003250 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07003251 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003252 ": Registered for IOC event notifications\n"));
3253 }
3254
Eric Mooredf9e0622007-01-29 09:46:21 -07003255 if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003256 dprintk((KERN_INFO MYNAM
3257 ": Registered for IOC reset notifications\n"));
3258 }
3259
3260 return pci_register_driver(&mptsas_driver);
3261}
3262
3263static void __exit
3264mptsas_exit(void)
3265{
3266 pci_unregister_driver(&mptsas_driver);
3267 sas_release_transport(mptsas_transport_template);
3268
3269 mpt_reset_deregister(mptsasDoneCtx);
3270 mpt_event_deregister(mptsasDoneCtx);
3271
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003272 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003273 mpt_deregister(mptsasInternalCtx);
3274 mpt_deregister(mptsasTaskCtx);
3275 mpt_deregister(mptsasDoneCtx);
3276}
3277
3278module_init(mptsas_init);
3279module_exit(mptsas_exit);