blob: be4eb8a308b7a13a05d36424f7752e4695210f36 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
3 * For use with LSI Logic PCI chip/adapter(s)
4 * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
5 *
6 * Copyright (c) 1999-2005 LSI Logic Corporation
7 * (mailto:mpt_linux_developer@lsil.com)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01008 * Copyright (c) 2005-2006 Dell
Christoph Hellwig0c33b272005-09-09 16:27:19 +02009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
51#include <linux/sched.h>
52#include <linux/workqueue.h>
53
54#include <scsi/scsi_cmnd.h>
55#include <scsi/scsi_device.h>
56#include <scsi/scsi_host.h>
57#include <scsi/scsi_transport_sas.h>
58
59#include "mptbase.h"
60#include "mptscsih.h"
61
62
63#define my_NAME "Fusion MPT SAS Host driver"
64#define my_VERSION MPT_LINUX_VERSION_COMMON
65#define MYNAM "mptsas"
66
67MODULE_AUTHOR(MODULEAUTHOR);
68MODULE_DESCRIPTION(my_NAME);
69MODULE_LICENSE("GPL");
70
71static int mpt_pq_filter;
72module_param(mpt_pq_filter, int, 0);
73MODULE_PARM_DESC(mpt_pq_filter,
74 "Enable peripheral qualifier filter: enable=1 "
75 "(default=0)");
76
77static int mpt_pt_clear;
78module_param(mpt_pt_clear, int, 0);
79MODULE_PARM_DESC(mpt_pt_clear,
80 "Clear persistency table: enable=1 "
81 "(default=MPTSCSIH_PT_CLEAR=0)");
82
83static int mptsasDoneCtx = -1;
84static int mptsasTaskCtx = -1;
85static int mptsasInternalCtx = -1; /* Used only for internal commands */
Christoph Hellwigda4fa652005-10-19 20:01:42 +020086static int mptsasMgmtCtx = -1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020087
88
Christoph Hellwig9a28f492006-01-13 18:04:41 +010089enum mptsas_hotplug_action {
90 MPTSAS_ADD_DEVICE,
91 MPTSAS_DEL_DEVICE,
Moore, Ericc73787ee2006-01-26 16:20:06 -070092 MPTSAS_ADD_RAID,
93 MPTSAS_DEL_RAID,
Christoph Hellwig9a28f492006-01-13 18:04:41 +010094};
95
96struct mptsas_hotplug_event {
97 struct work_struct work;
98 MPT_ADAPTER *ioc;
99 enum mptsas_hotplug_action event_type;
100 u64 sas_address;
101 u32 channel;
102 u32 id;
103 u32 device_info;
104 u16 handle;
105 u16 parent_handle;
106 u8 phy_id;
Moore, Ericf44e5462006-03-14 09:14:21 -0700107 u8 phys_disk_num;
108 u8 phys_disk_num_valid;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100109};
110
Moore, Erice6b2d762006-03-14 09:14:24 -0700111struct mptsas_discovery_event {
112 struct work_struct work;
113 MPT_ADAPTER *ioc;
114};
115
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200116/*
117 * SAS topology structures
118 *
119 * The MPT Fusion firmware interface spreads information about the
120 * SAS topology over many manufacture pages, thus we need some data
121 * structure to collect it and process it for the SAS transport class.
122 */
123
124struct mptsas_devinfo {
125 u16 handle; /* unique id to address this device */
Moore, Ericc73787ee2006-01-26 16:20:06 -0700126 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100127 u16 handle_enclosure; /* enclosure identifier of the enclosure */
128 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200129 u8 phy_id; /* phy number of parent device */
130 u8 port_id; /* sas physical port this device
131 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100132 u8 id; /* logical target id of this device */
133 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200134 u64 sas_address; /* WWN of this device,
135 SATA is assigned by HBA,expander */
136 u32 device_info; /* bitfield detailed info about this device */
137};
138
139struct mptsas_phyinfo {
140 u8 phy_id; /* phy index */
141 u8 port_id; /* port number this phy is part of */
142 u8 negotiated_link_rate; /* nego'd link rate for this phy */
143 u8 hw_link_rate; /* hardware max/min phys link rate */
144 u8 programmed_link_rate; /* programmed max/min phy link rate */
145 struct mptsas_devinfo identify; /* point to phy device info */
146 struct mptsas_devinfo attached; /* point to attached device info */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100147 struct sas_phy *phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200148 struct sas_rphy *rphy;
Moore, Ericf44e5462006-03-14 09:14:21 -0700149 struct scsi_target *starget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200150};
151
152struct mptsas_portinfo {
153 struct list_head list;
154 u16 handle; /* unique id to address this */
155 u8 num_phys; /* number of phys */
156 struct mptsas_phyinfo *phy_info;
157};
158
Christoph Hellwige3094442006-02-16 13:25:36 +0100159struct mptsas_enclosure {
160 u64 enclosure_logical_id; /* The WWN for the enclosure */
161 u16 enclosure_handle; /* unique id to address this */
162 u16 flags; /* details enclosure management */
163 u16 num_slot; /* num slots */
164 u16 start_slot; /* first slot */
165 u8 start_id; /* starting logical target id */
166 u8 start_channel; /* starting logical channel id */
167 u8 sep_id; /* SEP device logical target id */
168 u8 sep_channel; /* SEP channel logical channel id */
169};
170
Christoph Hellwigb5141122005-10-28 22:07:41 +0200171#ifdef SASDEBUG
172static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
173{
174 printk("---- IO UNIT PAGE 0 ------------\n");
175 printk("Handle=0x%X\n",
176 le16_to_cpu(phy_data->AttachedDeviceHandle));
177 printk("Controller Handle=0x%X\n",
178 le16_to_cpu(phy_data->ControllerDevHandle));
179 printk("Port=0x%X\n", phy_data->Port);
180 printk("Port Flags=0x%X\n", phy_data->PortFlags);
181 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
182 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
183 printk("Controller PHY Device Info=0x%X\n",
184 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
185 printk("DiscoveryStatus=0x%X\n",
186 le32_to_cpu(phy_data->DiscoveryStatus));
187 printk("\n");
188}
189
190static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
191{
192 __le64 sas_address;
193
194 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
195
196 printk("---- SAS PHY PAGE 0 ------------\n");
197 printk("Attached Device Handle=0x%X\n",
198 le16_to_cpu(pg0->AttachedDevHandle));
199 printk("SAS Address=0x%llX\n",
200 (unsigned long long)le64_to_cpu(sas_address));
201 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
202 printk("Attached Device Info=0x%X\n",
203 le32_to_cpu(pg0->AttachedDeviceInfo));
204 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
205 printk("Change Count=0x%X\n", pg0->ChangeCount);
206 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
207 printk("\n");
208}
209
210static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
211{
212 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200213 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
214 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200215 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200216 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
217 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
218 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200219}
220
221static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
222{
223 __le64 sas_address;
224
225 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
226
227 printk("---- SAS DEVICE PAGE 0 ---------\n");
228 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100229 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200230 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
231 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
232 printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
233 printk("Target ID=0x%X\n", pg0->TargetID);
234 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200235 /* The PhyNum field specifies the PHY number of the parent
236 * device this device is linked to
237 */
238 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
239 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200240 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
241 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
242 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
243 printk("\n");
244}
245
246static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
247{
248 printk("---- SAS EXPANDER PAGE 1 ------------\n");
249
250 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200251 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
253 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
254 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
255 printk("Owner Device Handle=0x%X\n",
256 le16_to_cpu(pg1->OwnerDevHandle));
257 printk("Attached Device Handle=0x%X\n",
258 le16_to_cpu(pg1->AttachedDevHandle));
259}
260#else
261#define mptsas_print_phy_data(phy_data) do { } while (0)
262#define mptsas_print_phy_pg0(pg0) do { } while (0)
263#define mptsas_print_phy_pg1(pg1) do { } while (0)
264#define mptsas_print_device_pg0(pg0) do { } while (0)
265#define mptsas_print_expander_pg1(pg1) do { } while (0)
266#endif
267
Christoph Hellwige3094442006-02-16 13:25:36 +0100268static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
269{
270 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
271 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
272}
273
274static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
275{
276 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
277 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
278}
279
Moore, Erice6b2d762006-03-14 09:14:24 -0700280/*
281 * mptsas_find_portinfo_by_handle
282 *
283 * This function should be called with the sas_topology_mutex already held
284 */
285static struct mptsas_portinfo *
286mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
287{
288 struct mptsas_portinfo *port_info, *rc=NULL;
289 int i;
290
291 list_for_each_entry(port_info, &ioc->sas_topology, list)
292 for (i = 0; i < port_info->num_phys; i++)
293 if (port_info->phy_info[i].identify.handle == handle) {
294 rc = port_info;
295 goto out;
296 }
297 out:
298 return rc;
299}
300
Christoph Hellwige3094442006-02-16 13:25:36 +0100301static int
Moore, Eric52435432006-03-14 09:14:15 -0700302mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100303 u32 form, u32 form_specific)
304{
305 ConfigExtendedPageHeader_t hdr;
306 CONFIGPARMS cfg;
307 SasEnclosurePage0_t *buffer;
308 dma_addr_t dma_handle;
309 int error;
310 __le64 le_identifier;
311
312 memset(&hdr, 0, sizeof(hdr));
313 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
314 hdr.PageNumber = 0;
315 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
316 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
317
318 cfg.cfghdr.ehdr = &hdr;
319 cfg.physAddr = -1;
320 cfg.pageAddr = form + form_specific;
321 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
322 cfg.dir = 0; /* read */
323 cfg.timeout = 10;
324
325 error = mpt_config(ioc, &cfg);
326 if (error)
327 goto out;
328 if (!hdr.ExtPageLength) {
329 error = -ENXIO;
330 goto out;
331 }
332
333 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
334 &dma_handle);
335 if (!buffer) {
336 error = -ENOMEM;
337 goto out;
338 }
339
340 cfg.physAddr = dma_handle;
341 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
342
343 error = mpt_config(ioc, &cfg);
344 if (error)
345 goto out_free_consistent;
346
347 /* save config data */
348 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
349 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
350 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
351 enclosure->flags = le16_to_cpu(buffer->Flags);
352 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
353 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
354 enclosure->start_id = buffer->StartTargetID;
355 enclosure->start_channel = buffer->StartBus;
356 enclosure->sep_id = buffer->SEPTargetID;
357 enclosure->sep_channel = buffer->SEPBus;
358
359 out_free_consistent:
360 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
361 buffer, dma_handle);
362 out:
363 return error;
364}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200365
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200366/*
367 * This is pretty ugly. We will be able to seriously clean it up
368 * once the DV code in mptscsih goes away and we can properly
369 * implement ->target_alloc.
370 */
371static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700372mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200373{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700374 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200375 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
376 struct sas_rphy *rphy;
377 struct mptsas_portinfo *p;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700378 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200379 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700380 struct scsi_target *starget;
Moore, Eric914c2d82006-03-14 09:19:36 -0700381 u32 target_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200382 int i;
383
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100384 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200385 if (!vdev) {
386 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
387 hd->ioc->name, sizeof(VirtDevice));
388 return -ENOMEM;
389 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700390 sdev->hostdata = vdev;
391 starget = scsi_target(sdev);
392 vtarget = starget->hostdata;
Moore, Eric914c2d82006-03-14 09:19:36 -0700393 vtarget->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700394 vdev->vtarget = vtarget;
395 if (vtarget->num_luns == 0) {
396 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
397 hd->Targets[sdev->id] = vtarget;
398 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200399
Moore, Eric816aa902006-01-13 16:25:20 -0700400 /*
401 RAID volumes placed beyond the last expected port.
402 */
403 if (sdev->channel == hd->ioc->num_ports) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700404 target_id = sdev->id;
405 vtarget->bus_id = 0;
Moore, Eric816aa902006-01-13 16:25:20 -0700406 vdev->lun = 0;
407 goto out;
408 }
409
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700410 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100411 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200412 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
413 for (i = 0; i < p->num_phys; i++) {
414 if (p->phy_info[i].attached.sas_address ==
415 rphy->identify.sas_address) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700416 target_id = p->phy_info[i].attached.id;
417 vtarget->bus_id = p->phy_info[i].attached.channel;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700418 vdev->lun = sdev->lun;
Moore, Ericf44e5462006-03-14 09:14:21 -0700419 p->phy_info[i].starget = sdev->sdev_target;
420 /*
421 * Exposing hidden disk (RAID)
422 */
423 if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
424 target_id = mptscsih_raid_id_to_num(hd,
425 target_id);
426 vdev->vtarget->tflags |=
427 MPT_TARGET_FLAGS_RAID_COMPONENT;
428 sdev->no_uld_attach = 1;
429 }
Moore, Eric914c2d82006-03-14 09:19:36 -0700430 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200431 goto out;
432 }
433 }
434 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100435 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200436
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200437 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100438 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200439
440 out:
Moore, Eric914c2d82006-03-14 09:19:36 -0700441 vtarget->target_id = target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700442 vtarget->num_luns++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200443 return 0;
444}
445
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100446static void
447mptsas_slave_destroy(struct scsi_device *sdev)
448{
449 struct Scsi_Host *host = sdev->host;
450 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700451 VirtDevice *vdev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100452
453 /*
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700454 * Issue target reset to flush firmware outstanding commands.
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100455 */
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700456 vdev = sdev->hostdata;
457 if (vdev->configured_lun){
458 if (mptscsih_TMHandler(hd,
459 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -0700460 vdev->vtarget->bus_id,
461 vdev->vtarget->target_id,
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700462 0, 0, 5 /* 5 second timeout */)
463 < 0){
464
465 /* The TM request failed!
466 * Fatal error case.
467 */
468 printk(MYIOC_s_WARN_FMT
469 "Error processing TaskMgmt id=%d TARGET_RESET\n",
470 hd->ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700471 vdev->vtarget->target_id);
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700472
473 hd->tmPending = 0;
474 hd->tmState = TM_STATE_NONE;
475 }
476 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100477 mptscsih_slave_destroy(sdev);
478}
479
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200480static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700481 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200482 .proc_name = "mptsas",
483 .proc_info = mptscsih_proc_info,
484 .name = "MPT SPI Host",
485 .info = mptscsih_info,
486 .queuecommand = mptscsih_qcmd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700487 .target_alloc = mptscsih_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200488 .slave_alloc = mptsas_slave_alloc,
489 .slave_configure = mptscsih_slave_configure,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700490 .target_destroy = mptscsih_target_destroy,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100491 .slave_destroy = mptsas_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200492 .change_queue_depth = mptscsih_change_queue_depth,
493 .eh_abort_handler = mptscsih_abort,
494 .eh_device_reset_handler = mptscsih_dev_reset,
495 .eh_bus_reset_handler = mptscsih_bus_reset,
496 .eh_host_reset_handler = mptscsih_host_reset,
497 .bios_param = mptscsih_bios_param,
498 .can_queue = MPT_FC_CAN_QUEUE,
499 .this_id = -1,
500 .sg_tablesize = MPT_SCSI_SG_DEPTH,
501 .max_sectors = 8192,
502 .cmd_per_lun = 7,
503 .use_clustering = ENABLE_CLUSTERING,
504};
505
Christoph Hellwigb5141122005-10-28 22:07:41 +0200506static int mptsas_get_linkerrors(struct sas_phy *phy)
507{
508 MPT_ADAPTER *ioc = phy_to_ioc(phy);
509 ConfigExtendedPageHeader_t hdr;
510 CONFIGPARMS cfg;
511 SasPhyPage1_t *buffer;
512 dma_addr_t dma_handle;
513 int error;
514
515 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
516 hdr.ExtPageLength = 0;
517 hdr.PageNumber = 1 /* page number 1*/;
518 hdr.Reserved1 = 0;
519 hdr.Reserved2 = 0;
520 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
521 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
522
523 cfg.cfghdr.ehdr = &hdr;
524 cfg.physAddr = -1;
525 cfg.pageAddr = phy->identify.phy_identifier;
526 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
527 cfg.dir = 0; /* read */
528 cfg.timeout = 10;
529
530 error = mpt_config(ioc, &cfg);
531 if (error)
532 return error;
533 if (!hdr.ExtPageLength)
534 return -ENXIO;
535
536 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
537 &dma_handle);
538 if (!buffer)
539 return -ENOMEM;
540
541 cfg.physAddr = dma_handle;
542 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
543
544 error = mpt_config(ioc, &cfg);
545 if (error)
546 goto out_free_consistent;
547
548 mptsas_print_phy_pg1(buffer);
549
550 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
551 phy->running_disparity_error_count =
552 le32_to_cpu(buffer->RunningDisparityErrorCount);
553 phy->loss_of_dword_sync_count =
554 le32_to_cpu(buffer->LossDwordSynchCount);
555 phy->phy_reset_problem_count =
556 le32_to_cpu(buffer->PhyResetProblemCount);
557
558 out_free_consistent:
559 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
560 buffer, dma_handle);
561 return error;
562}
563
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200564static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
565 MPT_FRAME_HDR *reply)
566{
567 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
568 if (reply != NULL) {
569 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
570 memcpy(ioc->sas_mgmt.reply, reply,
571 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
572 }
573 complete(&ioc->sas_mgmt.done);
574 return 1;
575}
576
577static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
578{
579 MPT_ADAPTER *ioc = phy_to_ioc(phy);
580 SasIoUnitControlRequest_t *req;
581 SasIoUnitControlReply_t *reply;
582 MPT_FRAME_HDR *mf;
583 MPIHeader_t *hdr;
584 unsigned long timeleft;
585 int error = -ERESTARTSYS;
586
587 /* not implemented for expanders */
588 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
589 return -ENXIO;
590
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100591 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200592 goto out;
593
594 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
595 if (!mf) {
596 error = -ENOMEM;
597 goto out_unlock;
598 }
599
600 hdr = (MPIHeader_t *) mf;
601 req = (SasIoUnitControlRequest_t *)mf;
602 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
603 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
604 req->MsgContext = hdr->MsgContext;
605 req->Operation = hard_reset ?
606 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
607 req->PhyNum = phy->identify.phy_identifier;
608
609 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
610
611 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
612 10 * HZ);
613 if (!timeleft) {
614 /* On timeout reset the board */
615 mpt_free_msg_frame(ioc, mf);
616 mpt_HardResetHandler(ioc, CAN_SLEEP);
617 error = -ETIMEDOUT;
618 goto out_unlock;
619 }
620
621 /* a reply frame is expected */
622 if ((ioc->sas_mgmt.status &
623 MPT_IOCTL_STATUS_RF_VALID) == 0) {
624 error = -ENXIO;
625 goto out_unlock;
626 }
627
628 /* process the completed Reply Message Frame */
629 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
630 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
631 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
632 __FUNCTION__,
633 reply->IOCStatus,
634 reply->IOCLogInfo);
635 error = -ENXIO;
636 goto out_unlock;
637 }
638
639 error = 0;
640
641 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100642 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200643 out:
644 return error;
645}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200646
Christoph Hellwige3094442006-02-16 13:25:36 +0100647static int
648mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
649{
650 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
651 int i, error;
652 struct mptsas_portinfo *p;
653 struct mptsas_enclosure enclosure_info;
654 u64 enclosure_handle;
655
656 mutex_lock(&ioc->sas_topology_mutex);
657 list_for_each_entry(p, &ioc->sas_topology, list) {
658 for (i = 0; i < p->num_phys; i++) {
659 if (p->phy_info[i].attached.sas_address ==
660 rphy->identify.sas_address) {
661 enclosure_handle = p->phy_info[i].
662 attached.handle_enclosure;
663 goto found_info;
664 }
665 }
666 }
667 mutex_unlock(&ioc->sas_topology_mutex);
668 return -ENXIO;
669
670 found_info:
671 mutex_unlock(&ioc->sas_topology_mutex);
672 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -0700673 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +0100674 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
675 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
676 if (!error)
677 *identifier = enclosure_info.enclosure_logical_id;
678 return error;
679}
680
681static int
682mptsas_get_bay_identifier(struct sas_rphy *rphy)
683{
684 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
685 struct mptsas_portinfo *p;
686 int i, rc;
687
688 mutex_lock(&ioc->sas_topology_mutex);
689 list_for_each_entry(p, &ioc->sas_topology, list) {
690 for (i = 0; i < p->num_phys; i++) {
691 if (p->phy_info[i].attached.sas_address ==
692 rphy->identify.sas_address) {
693 rc = p->phy_info[i].attached.slot;
694 goto out;
695 }
696 }
697 }
698 rc = -ENXIO;
699 out:
700 mutex_unlock(&ioc->sas_topology_mutex);
701 return rc;
702}
703
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200704static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +0200705 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +0100706 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
707 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200708 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200709};
710
711static struct scsi_transport_template *mptsas_transport_template;
712
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200713static int
714mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
715{
716 ConfigExtendedPageHeader_t hdr;
717 CONFIGPARMS cfg;
718 SasIOUnitPage0_t *buffer;
719 dma_addr_t dma_handle;
720 int error, i;
721
722 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
723 hdr.ExtPageLength = 0;
724 hdr.PageNumber = 0;
725 hdr.Reserved1 = 0;
726 hdr.Reserved2 = 0;
727 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
728 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
729
730 cfg.cfghdr.ehdr = &hdr;
731 cfg.physAddr = -1;
732 cfg.pageAddr = 0;
733 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
734 cfg.dir = 0; /* read */
735 cfg.timeout = 10;
736
737 error = mpt_config(ioc, &cfg);
738 if (error)
739 goto out;
740 if (!hdr.ExtPageLength) {
741 error = -ENXIO;
742 goto out;
743 }
744
745 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
746 &dma_handle);
747 if (!buffer) {
748 error = -ENOMEM;
749 goto out;
750 }
751
752 cfg.physAddr = dma_handle;
753 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
754
755 error = mpt_config(ioc, &cfg);
756 if (error)
757 goto out_free_consistent;
758
759 port_info->num_phys = buffer->NumPhys;
760 port_info->phy_info = kcalloc(port_info->num_phys,
761 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
762 if (!port_info->phy_info) {
763 error = -ENOMEM;
764 goto out_free_consistent;
765 }
766
Moore, Ericdb9c9172006-03-14 09:14:18 -0700767 if (port_info->num_phys)
768 port_info->handle =
769 le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200770 for (i = 0; i < port_info->num_phys; i++) {
771 mptsas_print_phy_data(&buffer->PhyData[i]);
772 port_info->phy_info[i].phy_id = i;
773 port_info->phy_info[i].port_id =
774 buffer->PhyData[i].Port;
775 port_info->phy_info[i].negotiated_link_rate =
776 buffer->PhyData[i].NegotiatedLinkRate;
777 }
778
779 out_free_consistent:
780 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
781 buffer, dma_handle);
782 out:
783 return error;
784}
785
786static int
787mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
788 u32 form, u32 form_specific)
789{
790 ConfigExtendedPageHeader_t hdr;
791 CONFIGPARMS cfg;
792 SasPhyPage0_t *buffer;
793 dma_addr_t dma_handle;
794 int error;
795
796 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
797 hdr.ExtPageLength = 0;
798 hdr.PageNumber = 0;
799 hdr.Reserved1 = 0;
800 hdr.Reserved2 = 0;
801 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
802 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
803
804 cfg.cfghdr.ehdr = &hdr;
805 cfg.dir = 0; /* read */
806 cfg.timeout = 10;
807
808 /* Get Phy Pg 0 for each Phy. */
809 cfg.physAddr = -1;
810 cfg.pageAddr = form + form_specific;
811 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
812
813 error = mpt_config(ioc, &cfg);
814 if (error)
815 goto out;
816
817 if (!hdr.ExtPageLength) {
818 error = -ENXIO;
819 goto out;
820 }
821
822 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
823 &dma_handle);
824 if (!buffer) {
825 error = -ENOMEM;
826 goto out;
827 }
828
829 cfg.physAddr = dma_handle;
830 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
831
832 error = mpt_config(ioc, &cfg);
833 if (error)
834 goto out_free_consistent;
835
836 mptsas_print_phy_pg0(buffer);
837
838 phy_info->hw_link_rate = buffer->HwLinkRate;
839 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
840 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
841 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
842
843 out_free_consistent:
844 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
845 buffer, dma_handle);
846 out:
847 return error;
848}
849
850static int
851mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
852 u32 form, u32 form_specific)
853{
854 ConfigExtendedPageHeader_t hdr;
855 CONFIGPARMS cfg;
856 SasDevicePage0_t *buffer;
857 dma_addr_t dma_handle;
858 __le64 sas_address;
859 int error;
860
861 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
862 hdr.ExtPageLength = 0;
863 hdr.PageNumber = 0;
864 hdr.Reserved1 = 0;
865 hdr.Reserved2 = 0;
866 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
867 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
868
869 cfg.cfghdr.ehdr = &hdr;
870 cfg.pageAddr = form + form_specific;
871 cfg.physAddr = -1;
872 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
873 cfg.dir = 0; /* read */
874 cfg.timeout = 10;
875
Moore, Ericdb9c9172006-03-14 09:14:18 -0700876 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200877 error = mpt_config(ioc, &cfg);
878 if (error)
879 goto out;
880 if (!hdr.ExtPageLength) {
881 error = -ENXIO;
882 goto out;
883 }
884
885 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
886 &dma_handle);
887 if (!buffer) {
888 error = -ENOMEM;
889 goto out;
890 }
891
892 cfg.physAddr = dma_handle;
893 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
894
895 error = mpt_config(ioc, &cfg);
896 if (error)
897 goto out_free_consistent;
898
899 mptsas_print_device_pg0(buffer);
900
901 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -0700902 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +0100903 device_info->handle_enclosure =
904 le16_to_cpu(buffer->EnclosureHandle);
905 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200906 device_info->phy_id = buffer->PhyNum;
907 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100908 device_info->id = buffer->TargetID;
909 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200910 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
911 device_info->sas_address = le64_to_cpu(sas_address);
912 device_info->device_info =
913 le32_to_cpu(buffer->DeviceInfo);
914
915 out_free_consistent:
916 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
917 buffer, dma_handle);
918 out:
919 return error;
920}
921
922static int
923mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
924 u32 form, u32 form_specific)
925{
926 ConfigExtendedPageHeader_t hdr;
927 CONFIGPARMS cfg;
928 SasExpanderPage0_t *buffer;
929 dma_addr_t dma_handle;
930 int error;
931
932 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
933 hdr.ExtPageLength = 0;
934 hdr.PageNumber = 0;
935 hdr.Reserved1 = 0;
936 hdr.Reserved2 = 0;
937 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
938 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
939
940 cfg.cfghdr.ehdr = &hdr;
941 cfg.physAddr = -1;
942 cfg.pageAddr = form + form_specific;
943 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
944 cfg.dir = 0; /* read */
945 cfg.timeout = 10;
946
Moore, Ericdb9c9172006-03-14 09:14:18 -0700947 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200948 error = mpt_config(ioc, &cfg);
949 if (error)
950 goto out;
951
952 if (!hdr.ExtPageLength) {
953 error = -ENXIO;
954 goto out;
955 }
956
957 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
958 &dma_handle);
959 if (!buffer) {
960 error = -ENOMEM;
961 goto out;
962 }
963
964 cfg.physAddr = dma_handle;
965 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
966
967 error = mpt_config(ioc, &cfg);
968 if (error)
969 goto out_free_consistent;
970
971 /* save config data */
972 port_info->num_phys = buffer->NumPhys;
973 port_info->handle = le16_to_cpu(buffer->DevHandle);
974 port_info->phy_info = kcalloc(port_info->num_phys,
975 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
976 if (!port_info->phy_info) {
977 error = -ENOMEM;
978 goto out_free_consistent;
979 }
980
981 out_free_consistent:
982 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
983 buffer, dma_handle);
984 out:
985 return error;
986}
987
988static int
989mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
990 u32 form, u32 form_specific)
991{
992 ConfigExtendedPageHeader_t hdr;
993 CONFIGPARMS cfg;
994 SasExpanderPage1_t *buffer;
995 dma_addr_t dma_handle;
996 int error;
997
998 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
999 hdr.ExtPageLength = 0;
1000 hdr.PageNumber = 1;
1001 hdr.Reserved1 = 0;
1002 hdr.Reserved2 = 0;
1003 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1004 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1005
1006 cfg.cfghdr.ehdr = &hdr;
1007 cfg.physAddr = -1;
1008 cfg.pageAddr = form + form_specific;
1009 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1010 cfg.dir = 0; /* read */
1011 cfg.timeout = 10;
1012
1013 error = mpt_config(ioc, &cfg);
1014 if (error)
1015 goto out;
1016
1017 if (!hdr.ExtPageLength) {
1018 error = -ENXIO;
1019 goto out;
1020 }
1021
1022 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1023 &dma_handle);
1024 if (!buffer) {
1025 error = -ENOMEM;
1026 goto out;
1027 }
1028
1029 cfg.physAddr = dma_handle;
1030 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1031
1032 error = mpt_config(ioc, &cfg);
1033 if (error)
1034 goto out_free_consistent;
1035
1036
1037 mptsas_print_expander_pg1(buffer);
1038
1039 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001040 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001041 phy_info->port_id = buffer->PhysicalPort;
1042 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1043 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1044 phy_info->hw_link_rate = buffer->HwLinkRate;
1045 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1046 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1047
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001048 out_free_consistent:
1049 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1050 buffer, dma_handle);
1051 out:
1052 return error;
1053}
1054
Moore, Ericc73787ee2006-01-26 16:20:06 -07001055/*
1056 * Returns true if there is a scsi end device
1057 */
1058static inline int
1059mptsas_is_end_device(struct mptsas_devinfo * attached)
1060{
1061 if ((attached->handle) &&
1062 (attached->device_info &
1063 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
1064 ((attached->device_info &
1065 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1066 (attached->device_info &
1067 MPI_SAS_DEVICE_INFO_STP_TARGET) |
1068 (attached->device_info &
1069 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
1070 return 1;
1071 else
1072 return 0;
1073}
1074
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001075static void
1076mptsas_parse_device_info(struct sas_identify *identify,
1077 struct mptsas_devinfo *device_info)
1078{
1079 u16 protocols;
1080
1081 identify->sas_address = device_info->sas_address;
1082 identify->phy_identifier = device_info->phy_id;
1083
1084 /*
1085 * Fill in Phy Initiator Port Protocol.
1086 * Bits 6:3, more than one bit can be set, fall through cases.
1087 */
1088 protocols = device_info->device_info & 0x78;
1089 identify->initiator_port_protocols = 0;
1090 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1091 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1092 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1093 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1094 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1095 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1096 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1097 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1098
1099 /*
1100 * Fill in Phy Target Port Protocol.
1101 * Bits 10:7, more than one bit can be set, fall through cases.
1102 */
1103 protocols = device_info->device_info & 0x780;
1104 identify->target_port_protocols = 0;
1105 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1106 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1107 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1108 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1109 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1110 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1111 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1112 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1113
1114 /*
1115 * Fill in Attached device type.
1116 */
1117 switch (device_info->device_info &
1118 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1119 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1120 identify->device_type = SAS_PHY_UNUSED;
1121 break;
1122 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1123 identify->device_type = SAS_END_DEVICE;
1124 break;
1125 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1126 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1127 break;
1128 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1129 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1130 break;
1131 }
1132}
1133
1134static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001135 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001136{
Moore, Erice6b2d762006-03-14 09:14:24 -07001137 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001138 struct sas_phy *phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001139 int error;
1140
Moore, Erice6b2d762006-03-14 09:14:24 -07001141 if (!dev)
1142 return -ENODEV;
1143
1144 if (!phy_info->phy) {
1145 phy = sas_phy_alloc(dev, index);
1146 if (!phy)
1147 return -ENOMEM;
1148 } else
1149 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001150
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001151 phy->port_identifier = phy_info->port_id;
1152 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001153
1154 /*
1155 * Set Negotiated link rate.
1156 */
1157 switch (phy_info->negotiated_link_rate) {
1158 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001159 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001160 break;
1161 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001162 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001163 break;
1164 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001165 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001166 break;
1167 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001168 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001169 break;
1170 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1171 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1172 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001173 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001174 break;
1175 }
1176
1177 /*
1178 * Set Max hardware link rate.
1179 */
1180 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1181 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001182 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001183 break;
1184 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001185 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001186 break;
1187 default:
1188 break;
1189 }
1190
1191 /*
1192 * Set Max programmed link rate.
1193 */
1194 switch (phy_info->programmed_link_rate &
1195 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1196 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001197 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001198 break;
1199 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001200 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001201 break;
1202 default:
1203 break;
1204 }
1205
1206 /*
1207 * Set Min hardware link rate.
1208 */
1209 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1210 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001211 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001212 break;
1213 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001214 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001215 break;
1216 default:
1217 break;
1218 }
1219
1220 /*
1221 * Set Min programmed link rate.
1222 */
1223 switch (phy_info->programmed_link_rate &
1224 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1225 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001226 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001227 break;
1228 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001229 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001230 break;
1231 default:
1232 break;
1233 }
1234
Moore, Erice6b2d762006-03-14 09:14:24 -07001235 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001236
Moore, Erice6b2d762006-03-14 09:14:24 -07001237 if (local)
1238 phy->local_attached = 1;
1239
1240 error = sas_phy_add(phy);
1241 if (error) {
1242 sas_phy_free(phy);
1243 return error;
1244 }
1245 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001246 }
1247
Moore, Erice6b2d762006-03-14 09:14:24 -07001248 if ((phy_info->attached.handle) &&
1249 (!phy_info->rphy)) {
1250
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001251 struct sas_rphy *rphy;
1252
Moore, Erice6b2d762006-03-14 09:14:24 -07001253 ioc = phy_to_ioc(phy_info->phy);
1254
1255 /*
1256 * Let the hotplug_work thread handle processing
1257 * the adding/removing of devices that occur
1258 * after start of day.
1259 */
1260 if (ioc->sas_discovery_runtime &&
1261 mptsas_is_end_device(&phy_info->attached))
1262 return 0;
1263
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001264 rphy = sas_rphy_alloc(phy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001265 if (!rphy)
1266 return 0; /* non-fatal: an rphy can be added later */
1267
1268 mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
1269 error = sas_rphy_add(rphy);
1270 if (error) {
1271 sas_rphy_free(rphy);
1272 return error;
1273 }
1274
1275 phy_info->rphy = rphy;
1276 }
1277
1278 return 0;
1279}
1280
1281static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001282mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001283{
Moore, Erice6b2d762006-03-14 09:14:24 -07001284 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001285 u32 handle = 0xFFFF;
1286 int error = -ENOMEM, i;
1287
Moore, Erice6b2d762006-03-14 09:14:24 -07001288 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1289 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001290 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001291
Moore, Erice6b2d762006-03-14 09:14:24 -07001292 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001293 if (error)
1294 goto out_free_port_info;
1295
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001296 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001297 port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
1298 if (!port_info) {
1299 port_info = hba;
1300 list_add_tail(&port_info->list, &ioc->sas_topology);
1301 } else {
1302 port_info->handle = hba->handle;
1303 for (i = 0; i < hba->num_phys; i++)
1304 port_info->phy_info[i].negotiated_link_rate =
1305 hba->phy_info[i].negotiated_link_rate;
1306 if (hba->phy_info)
1307 kfree(hba->phy_info);
1308 kfree(hba);
1309 hba = NULL;
1310 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001311 mutex_unlock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001312 ioc->num_ports = port_info->num_phys;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001313
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001314 for (i = 0; i < port_info->num_phys; i++) {
1315 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1316 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1317 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1318
1319 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1320 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1321 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001322 port_info->phy_info[i].identify.phy_id =
1323 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001324 handle = port_info->phy_info[i].identify.handle;
1325
1326 if (port_info->phy_info[i].attached.handle) {
1327 mptsas_sas_device_pg0(ioc,
1328 &port_info->phy_info[i].attached,
1329 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1330 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1331 port_info->phy_info[i].attached.handle);
1332 }
1333
1334 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07001335 &port_info->phy_info[i], ioc->sas_index, 1);
1336 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001337 }
1338
1339 return 0;
1340
1341 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001342 if (hba)
1343 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001344 out:
1345 return error;
1346}
1347
1348static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001349mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001350{
Moore, Erice6b2d762006-03-14 09:14:24 -07001351 struct mptsas_portinfo *port_info, *p, *ex;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001352 int error = -ENOMEM, i, j;
1353
Moore, Erice6b2d762006-03-14 09:14:24 -07001354 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1355 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001356 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001357
Moore, Erice6b2d762006-03-14 09:14:24 -07001358 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001359 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1360 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1361 if (error)
1362 goto out_free_port_info;
1363
Moore, Erice6b2d762006-03-14 09:14:24 -07001364 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001365
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001366 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001367 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1368 if (!port_info) {
1369 port_info = ex;
1370 list_add_tail(&port_info->list, &ioc->sas_topology);
1371 } else {
1372 port_info->handle = ex->handle;
1373 if (ex->phy_info)
1374 kfree(ex->phy_info);
1375 kfree(ex);
1376 ex = NULL;
1377 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001378 mutex_unlock(&ioc->sas_topology_mutex);
1379
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001380 for (i = 0; i < port_info->num_phys; i++) {
1381 struct device *parent;
1382
1383 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1384 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1385 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1386
1387 if (port_info->phy_info[i].identify.handle) {
1388 mptsas_sas_device_pg0(ioc,
1389 &port_info->phy_info[i].identify,
1390 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1391 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1392 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001393 port_info->phy_info[i].identify.phy_id =
1394 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001395 }
1396
1397 if (port_info->phy_info[i].attached.handle) {
1398 mptsas_sas_device_pg0(ioc,
1399 &port_info->phy_info[i].attached,
1400 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1401 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1402 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001403 port_info->phy_info[i].attached.phy_id =
1404 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001405 }
1406
1407 /*
1408 * If we find a parent port handle this expander is
1409 * attached to another expander, else it hangs of the
1410 * HBA phys.
1411 */
1412 parent = &ioc->sh->shost_gendev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001413 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001414 list_for_each_entry(p, &ioc->sas_topology, list) {
1415 for (j = 0; j < p->num_phys; j++) {
1416 if (port_info->phy_info[i].identify.handle ==
1417 p->phy_info[j].attached.handle)
1418 parent = &p->phy_info[j].rphy->dev;
1419 }
1420 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001421 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001422
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001423 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001424 ioc->sas_index, 0);
1425 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001426 }
1427
1428 return 0;
1429
1430 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001431 if (ex) {
1432 if (ex->phy_info)
1433 kfree(ex->phy_info);
1434 kfree(ex);
1435 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001436 out:
1437 return error;
1438}
1439
Moore, Erice6b2d762006-03-14 09:14:24 -07001440/*
1441 * mptsas_delete_expander_phys
1442 *
1443 *
1444 * This will traverse topology, and remove expanders
1445 * that are no longer present
1446 */
1447static void
1448mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1449{
1450 struct mptsas_portinfo buffer;
1451 struct mptsas_portinfo *port_info, *n, *parent;
1452 int i;
1453
1454 mutex_lock(&ioc->sas_topology_mutex);
1455 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1456
1457 if (port_info->phy_info &&
1458 (!(port_info->phy_info[0].identify.device_info &
1459 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1460 continue;
1461
1462 if (mptsas_sas_expander_pg0(ioc, &buffer,
1463 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1464 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1465
1466 /*
1467 * Obtain the port_info instance to the parent port
1468 */
1469 parent = mptsas_find_portinfo_by_handle(ioc,
1470 port_info->phy_info[0].identify.handle_parent);
1471
1472 if (!parent)
1473 goto next_port;
1474
1475 /*
1476 * Delete rphys in the parent that point
1477 * to this expander. The transport layer will
1478 * cleanup all the children.
1479 */
1480 for (i = 0; i < parent->num_phys; i++) {
1481 if ((!parent->phy_info[i].rphy) ||
1482 (parent->phy_info[i].attached.sas_address !=
1483 port_info->phy_info[i].identify.sas_address))
1484 continue;
1485 sas_rphy_delete(parent->phy_info[i].rphy);
1486 memset(&parent->phy_info[i].attached, 0,
1487 sizeof(struct mptsas_devinfo));
1488 parent->phy_info[i].rphy = NULL;
1489 parent->phy_info[i].starget = NULL;
1490 }
1491 next_port:
1492 list_del(&port_info->list);
1493 if (port_info->phy_info)
1494 kfree(port_info->phy_info);
1495 kfree(port_info);
1496 }
1497 /*
1498 * Free this memory allocated from inside
1499 * mptsas_sas_expander_pg0
1500 */
1501 if (buffer.phy_info)
1502 kfree(buffer.phy_info);
1503 }
1504 mutex_unlock(&ioc->sas_topology_mutex);
1505}
1506
1507/*
1508 * Start of day discovery
1509 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001510static void
1511mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1512{
1513 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001514 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001515
Moore, Erice6b2d762006-03-14 09:14:24 -07001516 mutex_lock(&ioc->sas_discovery_mutex);
1517 mptsas_probe_hba_phys(ioc);
1518 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001519 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001520 /*
1521 Reporting RAID volumes.
1522 */
1523 if (!ioc->raid_data.pIocPg2)
1524 goto out;
1525 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1526 goto out;
1527 for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1528 scsi_add_device(ioc->sh, ioc->num_ports,
1529 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
1530 }
1531 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07001532 mutex_unlock(&ioc->sas_discovery_mutex);
1533}
1534
1535/*
1536 * Work queue thread to handle Runtime discovery
1537 * Mere purpose is the hot add/delete of expanders
1538 */
1539static void
1540mptscsih_discovery_work(void * arg)
1541{
1542 struct mptsas_discovery_event *ev = arg;
1543 MPT_ADAPTER *ioc = ev->ioc;
1544 u32 handle = 0xFFFF;
1545
1546 mutex_lock(&ioc->sas_discovery_mutex);
1547 ioc->sas_discovery_runtime=1;
1548 mptsas_delete_expander_phys(ioc);
1549 mptsas_probe_hba_phys(ioc);
1550 while (!mptsas_probe_expander_phys(ioc, &handle))
1551 ;
1552 kfree(ev);
1553 ioc->sas_discovery_runtime=0;
1554 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001555}
1556
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001557static struct mptsas_phyinfo *
1558mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
1559{
1560 struct mptsas_portinfo *port_info;
1561 struct mptsas_devinfo device_info;
1562 struct mptsas_phyinfo *phy_info = NULL;
1563 int i, error;
1564
1565 /*
1566 * Retrieve the parent sas_address
1567 */
1568 error = mptsas_sas_device_pg0(ioc, &device_info,
1569 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1570 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1571 parent_handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001572 if (error)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001573 return NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001574
1575 /*
1576 * The phy_info structures are never deallocated during lifetime of
1577 * a host, so the code below is safe without additional refcounting.
1578 */
1579 mutex_lock(&ioc->sas_topology_mutex);
1580 list_for_each_entry(port_info, &ioc->sas_topology, list) {
1581 for (i = 0; i < port_info->num_phys; i++) {
1582 if (port_info->phy_info[i].identify.sas_address ==
1583 device_info.sas_address &&
1584 port_info->phy_info[i].phy_id == phy_id) {
1585 phy_info = &port_info->phy_info[i];
1586 break;
1587 }
1588 }
1589 }
1590 mutex_unlock(&ioc->sas_topology_mutex);
1591
1592 return phy_info;
1593}
1594
1595static struct mptsas_phyinfo *
Moore, Ericc73787ee2006-01-26 16:20:06 -07001596mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001597{
1598 struct mptsas_portinfo *port_info;
1599 struct mptsas_phyinfo *phy_info = NULL;
1600 int i;
1601
1602 /*
1603 * The phy_info structures are never deallocated during lifetime of
1604 * a host, so the code below is safe without additional refcounting.
1605 */
1606 mutex_lock(&ioc->sas_topology_mutex);
1607 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Moore, Ericc73787ee2006-01-26 16:20:06 -07001608 for (i = 0; i < port_info->num_phys; i++)
1609 if (mptsas_is_end_device(&port_info->phy_info[i].attached))
1610 if (port_info->phy_info[i].attached.id == id) {
1611 phy_info = &port_info->phy_info[i];
1612 break;
1613 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001614 }
1615 mutex_unlock(&ioc->sas_topology_mutex);
1616
1617 return phy_info;
1618}
1619
Moore, Eric4b766472006-03-14 09:14:12 -07001620/*
1621 * Work queue thread to clear the persitency table
1622 */
1623static void
1624mptscsih_sas_persist_clear_table(void * arg)
1625{
1626 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
1627
1628 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
1629}
1630
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001631static void
Moore, Ericf44e5462006-03-14 09:14:21 -07001632mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
1633{
1634 sdev->no_uld_attach = data ? 1 : 0;
1635 scsi_device_reprobe(sdev);
1636}
1637
1638static void
1639mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
1640{
1641 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
1642 mptsas_reprobe_lun);
1643}
1644
Moore, Erice6b2d762006-03-14 09:14:24 -07001645
1646/*
1647 * Work queue thread to handle SAS hotplug events
1648 */
Moore, Ericf44e5462006-03-14 09:14:21 -07001649static void
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001650mptsas_hotplug_work(void *arg)
1651{
1652 struct mptsas_hotplug_event *ev = arg;
1653 MPT_ADAPTER *ioc = ev->ioc;
1654 struct mptsas_phyinfo *phy_info;
1655 struct sas_rphy *rphy;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001656 struct scsi_device *sdev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001657 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001658 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07001659 VirtTarget *vtarget;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001660
Moore, Erice6b2d762006-03-14 09:14:24 -07001661 mutex_lock(&ioc->sas_discovery_mutex);
1662
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001663 switch (ev->event_type) {
1664 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001665
Moore, Ericc73787ee2006-01-26 16:20:06 -07001666 phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001667
Moore, Ericf44e5462006-03-14 09:14:21 -07001668 /*
1669 * Sanity checks, for non-existing phys and remote rphys.
1670 */
1671 if (!phy_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001672 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07001673 if (!phy_info->rphy)
1674 break;
1675 if (phy_info->starget) {
1676 vtarget = phy_info->starget->hostdata;
1677
1678 if (!vtarget)
1679 break;
1680 /*
1681 * Handling RAID components
1682 */
1683 if (ev->phys_disk_num_valid) {
1684 vtarget->target_id = ev->phys_disk_num;
1685 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
1686 mptsas_reprobe_target(vtarget->starget, 1);
1687 break;
1688 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001689 }
1690
Moore, Ericc73787ee2006-01-26 16:20:06 -07001691 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1692 ds = "ssp";
1693 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1694 ds = "stp";
1695 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1696 ds = "sata";
1697
1698 printk(MYIOC_s_INFO_FMT
1699 "removing %s device, channel %d, id %d, phy %d\n",
1700 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
1701
Moore, Ericf44e5462006-03-14 09:14:21 -07001702 sas_rphy_delete(phy_info->rphy);
1703 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
1704 phy_info->rphy = NULL;
1705 phy_info->starget = NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001706 break;
1707 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07001708
1709 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01001710 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07001711 */
Christoph Hellwige3094442006-02-16 13:25:36 +01001712 if (mptsas_sas_device_pg0(ioc, &sas_device,
1713 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
1714 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
1715 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001716
1717 phy_info = mptsas_find_phyinfo_by_parent(ioc,
Christoph Hellwige3094442006-02-16 13:25:36 +01001718 sas_device.handle_parent, sas_device.phy_id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001719
1720 if (!phy_info) {
1721 u32 handle = 0xFFFF;
1722
1723 /*
1724 * Its possible when an expander has been hot added
1725 * containing attached devices, the sas firmware
1726 * may send a RC_ADDED event prior to the
1727 * DISCOVERY STOP event. If that occurs, our
1728 * view of the topology in the driver in respect to this
1729 * expander might of not been setup, and we hit this
1730 * condition.
1731 * Therefore, this code kicks off discovery to
1732 * refresh the data.
1733 * Then again, we check whether the parent phy has
1734 * been created.
1735 */
1736 ioc->sas_discovery_runtime=1;
1737 mptsas_delete_expander_phys(ioc);
1738 mptsas_probe_hba_phys(ioc);
1739 while (!mptsas_probe_expander_phys(ioc, &handle))
1740 ;
1741 ioc->sas_discovery_runtime=0;
1742
1743 phy_info = mptsas_find_phyinfo_by_parent(ioc,
1744 sas_device.handle_parent, sas_device.phy_id);
1745 if (!phy_info)
1746 break;
1747 }
1748
Moore, Ericf44e5462006-03-14 09:14:21 -07001749 if (phy_info->starget) {
1750 vtarget = phy_info->starget->hostdata;
1751
1752 if (!vtarget)
1753 break;
1754 /*
1755 * Handling RAID components
1756 */
1757 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1758 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
1759 vtarget->target_id = ev->id;
1760 mptsas_reprobe_target(phy_info->starget, 0);
1761 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001762 break;
1763 }
1764
Moore, Ericf44e5462006-03-14 09:14:21 -07001765 if (phy_info->rphy)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001766 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001767
Christoph Hellwige3094442006-02-16 13:25:36 +01001768 memcpy(&phy_info->attached, &sas_device,
1769 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001770
Moore, Ericc73787ee2006-01-26 16:20:06 -07001771 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1772 ds = "ssp";
1773 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1774 ds = "stp";
1775 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1776 ds = "sata";
1777
1778 printk(MYIOC_s_INFO_FMT
1779 "attaching %s device, channel %d, id %d, phy %d\n",
1780 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
1781
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001782 rphy = sas_rphy_alloc(phy_info->phy);
1783 if (!rphy)
1784 break; /* non-fatal: an rphy can be added later */
1785
1786 mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
1787 if (sas_rphy_add(rphy)) {
1788 sas_rphy_free(rphy);
1789 break;
1790 }
1791
1792 phy_info->rphy = rphy;
1793 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001794 case MPTSAS_ADD_RAID:
1795 sdev = scsi_device_lookup(
1796 ioc->sh,
1797 ioc->num_ports,
1798 ev->id,
1799 0);
1800 if (sdev) {
1801 scsi_device_put(sdev);
1802 break;
1803 }
1804 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001805 "attaching raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001806 ioc->name, ioc->num_ports, ev->id);
1807 scsi_add_device(ioc->sh,
1808 ioc->num_ports,
1809 ev->id,
1810 0);
1811 mpt_findImVolumes(ioc);
1812 break;
1813 case MPTSAS_DEL_RAID:
1814 sdev = scsi_device_lookup(
1815 ioc->sh,
1816 ioc->num_ports,
1817 ev->id,
1818 0);
1819 if (!sdev)
1820 break;
1821 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001822 "removing raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001823 ioc->name, ioc->num_ports, ev->id);
1824 scsi_remove_device(sdev);
1825 scsi_device_put(sdev);
1826 mpt_findImVolumes(ioc);
1827 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001828 }
1829
1830 kfree(ev);
Moore, Erice6b2d762006-03-14 09:14:24 -07001831 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001832}
1833
1834static void
1835mptscsih_send_sas_event(MPT_ADAPTER *ioc,
1836 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1837{
1838 struct mptsas_hotplug_event *ev;
1839 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
1840 __le64 sas_address;
1841
1842 if ((device_info &
1843 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
1844 MPI_SAS_DEVICE_INFO_STP_TARGET |
1845 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
1846 return;
1847
Moore, Eric4b766472006-03-14 09:14:12 -07001848 switch (sas_event_data->ReasonCode) {
1849 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
1850 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
1851 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1852 if (!ev) {
1853 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1854 break;
1855 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001856
Moore, Eric4b766472006-03-14 09:14:12 -07001857 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1858 ev->ioc = ioc;
1859 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
1860 ev->parent_handle =
1861 le16_to_cpu(sas_event_data->ParentDevHandle);
1862 ev->channel = sas_event_data->Bus;
1863 ev->id = sas_event_data->TargetID;
1864 ev->phy_id = sas_event_data->PhyNum;
1865 memcpy(&sas_address, &sas_event_data->SASAddress,
1866 sizeof(__le64));
1867 ev->sas_address = le64_to_cpu(sas_address);
1868 ev->device_info = device_info;
1869
1870 if (sas_event_data->ReasonCode &
1871 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
1872 ev->event_type = MPTSAS_ADD_DEVICE;
1873 else
1874 ev->event_type = MPTSAS_DEL_DEVICE;
1875 schedule_work(&ev->work);
1876 break;
1877 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
1878 /*
1879 * Persistent table is full.
1880 */
1881 INIT_WORK(&ioc->mptscsih_persistTask,
1882 mptscsih_sas_persist_clear_table,
1883 (void *)ioc);
1884 schedule_work(&ioc->mptscsih_persistTask);
1885 break;
1886 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
1887 /* TODO */
1888 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
1889 /* TODO */
1890 default:
1891 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001892 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001893}
1894
Moore, Ericc73787ee2006-01-26 16:20:06 -07001895static void
1896mptscsih_send_raid_event(MPT_ADAPTER *ioc,
1897 EVENT_DATA_RAID *raid_event_data)
1898{
1899 struct mptsas_hotplug_event *ev;
1900 RAID_VOL0_STATUS * volumeStatus;
1901
1902 if (ioc->bus_type != SAS)
1903 return;
1904
1905 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1906 if (!ev) {
1907 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1908 return;
1909 }
1910
1911 memset(ev,0,sizeof(struct mptsas_hotplug_event));
1912 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1913 ev->ioc = ioc;
1914 ev->id = raid_event_data->VolumeID;
1915
1916 switch (raid_event_data->ReasonCode) {
1917 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
1918 ev->event_type = MPTSAS_ADD_DEVICE;
1919 break;
1920 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07001921 ioc->raid_data.isRaid = 1;
1922 ev->phys_disk_num_valid = 1;
1923 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001924 ev->event_type = MPTSAS_DEL_DEVICE;
1925 break;
1926 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
1927 ev->event_type = MPTSAS_DEL_RAID;
1928 break;
1929 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
1930 ev->event_type = MPTSAS_ADD_RAID;
1931 break;
1932 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
1933 volumeStatus = (RAID_VOL0_STATUS *) &
1934 raid_event_data->SettingsStatus;
1935 ev->event_type = (volumeStatus->State ==
1936 MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
1937 MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
1938 break;
1939 default:
1940 break;
1941 }
1942 schedule_work(&ev->work);
1943}
1944
Moore, Erice6b2d762006-03-14 09:14:24 -07001945static void
1946mptscsih_send_discovery(MPT_ADAPTER *ioc,
1947 EVENT_DATA_SAS_DISCOVERY *discovery_data)
1948{
1949 struct mptsas_discovery_event *ev;
1950
1951 /*
1952 * DiscoveryStatus
1953 *
1954 * This flag will be non-zero when firmware
1955 * kicks off discovery, and return to zero
1956 * once its completed.
1957 */
1958 if (discovery_data->DiscoveryStatus)
1959 return;
1960
1961 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1962 if (!ev)
1963 return;
1964 memset(ev,0,sizeof(struct mptsas_discovery_event));
1965 INIT_WORK(&ev->work, mptscsih_discovery_work, ev);
1966 ev->ioc = ioc;
1967 schedule_work(&ev->work);
1968};
1969
1970
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001971static int
1972mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
1973{
Moore, Ericc73787ee2006-01-26 16:20:06 -07001974 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001975 u8 event = le32_to_cpu(reply->Event) & 0xFF;
1976
1977 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07001978 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001979
Moore, Erice6b2d762006-03-14 09:14:24 -07001980 /*
1981 * sas_discovery_ignore_events
1982 *
1983 * This flag is to prevent anymore processing of
1984 * sas events once mptsas_remove function is called.
1985 */
1986 if (ioc->sas_discovery_ignore_events) {
1987 rc = mptscsih_event_process(ioc, reply);
1988 goto out;
1989 }
1990
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001991 switch (event) {
1992 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1993 mptscsih_send_sas_event(ioc,
1994 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001995 break;
1996 case MPI_EVENT_INTEGRATED_RAID:
1997 mptscsih_send_raid_event(ioc,
1998 (EVENT_DATA_RAID *)reply->Data);
1999 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002000 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2001 INIT_WORK(&ioc->mptscsih_persistTask,
2002 mptscsih_sas_persist_clear_table,
2003 (void *)ioc);
2004 schedule_work(&ioc->mptscsih_persistTask);
2005 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002006 case MPI_EVENT_SAS_DISCOVERY:
Moore, Erice6b2d762006-03-14 09:14:24 -07002007 mptscsih_send_discovery(ioc,
2008 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2009 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002010 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002011 rc = mptscsih_event_process(ioc, reply);
2012 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002013 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002014 out:
2015
2016 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002017}
2018
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002019static int
2020mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2021{
2022 struct Scsi_Host *sh;
2023 MPT_SCSI_HOST *hd;
2024 MPT_ADAPTER *ioc;
2025 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002026 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002027 int numSGE = 0;
2028 int scale;
2029 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002030 int error=0;
2031 int r;
2032
2033 r = mpt_attach(pdev,id);
2034 if (r)
2035 return r;
2036
2037 ioc = pci_get_drvdata(pdev);
2038 ioc->DoneCtx = mptsasDoneCtx;
2039 ioc->TaskCtx = mptsasTaskCtx;
2040 ioc->InternalCtx = mptsasInternalCtx;
2041
2042 /* Added sanity check on readiness of the MPT adapter.
2043 */
2044 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2045 printk(MYIOC_s_WARN_FMT
2046 "Skipping because it's not operational!\n",
2047 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002048 error = -ENODEV;
2049 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002050 }
2051
2052 if (!ioc->active) {
2053 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2054 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002055 error = -ENODEV;
2056 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002057 }
2058
2059 /* Sanity check - ensure at least 1 port is INITIATOR capable
2060 */
2061 ioc_cap = 0;
2062 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2063 if (ioc->pfacts[ii].ProtocolFlags &
2064 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2065 ioc_cap++;
2066 }
2067
2068 if (!ioc_cap) {
2069 printk(MYIOC_s_WARN_FMT
2070 "Skipping ioc=%p because SCSI Initiator mode "
2071 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002072 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002073 }
2074
2075 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2076 if (!sh) {
2077 printk(MYIOC_s_WARN_FMT
2078 "Unable to register controller with SCSI subsystem\n",
2079 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002080 error = -1;
2081 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002082 }
2083
2084 spin_lock_irqsave(&ioc->FreeQlock, flags);
2085
2086 /* Attach the SCSI Host to the IOC structure
2087 */
2088 ioc->sh = sh;
2089
2090 sh->io_port = 0;
2091 sh->n_io_port = 0;
2092 sh->irq = 0;
2093
2094 /* set 16 byte cdb's */
2095 sh->max_cmd_len = 16;
2096
2097 sh->max_id = ioc->pfacts->MaxDevices + 1;
2098
2099 sh->transportt = mptsas_transport_template;
2100
2101 sh->max_lun = MPT_LAST_LUN + 1;
2102 sh->max_channel = 0;
2103 sh->this_id = ioc->pfacts[0].PortSCSIID;
2104
2105 /* Required entry.
2106 */
2107 sh->unique_id = ioc->id;
2108
2109 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002110 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002111 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002112 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002113 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002114
2115 /* Verify that we won't exceed the maximum
2116 * number of chain buffers
2117 * We can optimize: ZZ = req_sz/sizeof(SGE)
2118 * For 32bit SGE's:
2119 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2120 * + (req_sz - 64)/sizeof(SGE)
2121 * A slightly different algorithm is required for
2122 * 64bit SGEs.
2123 */
2124 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2125 if (sizeof(dma_addr_t) == sizeof(u64)) {
2126 numSGE = (scale - 1) *
2127 (ioc->facts.MaxChainDepth-1) + scale +
2128 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2129 sizeof(u32));
2130 } else {
2131 numSGE = 1 + (scale - 1) *
2132 (ioc->facts.MaxChainDepth-1) + scale +
2133 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2134 sizeof(u32));
2135 }
2136
2137 if (numSGE < sh->sg_tablesize) {
2138 /* Reset this value */
2139 dprintk((MYIOC_s_INFO_FMT
2140 "Resetting sg_tablesize to %d from %d\n",
2141 ioc->name, numSGE, sh->sg_tablesize));
2142 sh->sg_tablesize = numSGE;
2143 }
2144
2145 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2146
2147 hd = (MPT_SCSI_HOST *) sh->hostdata;
2148 hd->ioc = ioc;
2149
2150 /* SCSI needs scsi_cmnd lookup table!
2151 * (with size equal to req_depth*PtrSz!)
2152 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002153 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2154 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002155 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002156 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002157 }
2158
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002159 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2160 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002161
2162 /* Allocate memory for the device structures.
2163 * A non-Null pointer at an offset
2164 * indicates a device exists.
2165 * max_id = 1 + maximum id (hosts.h)
2166 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002167 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
2168 if (!hd->Targets) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002169 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002170 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002171 }
2172
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002173 dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002174
2175 /* Clear the TM flags
2176 */
2177 hd->tmPending = 0;
2178 hd->tmState = TM_STATE_NONE;
2179 hd->resetPending = 0;
2180 hd->abortSCpnt = NULL;
2181
2182 /* Clear the pointer used to store
2183 * single-threaded commands, i.e., those
2184 * issued during a bus scan, dv and
2185 * configuration pages.
2186 */
2187 hd->cmdPtr = NULL;
2188
2189 /* Initialize this SCSI Hosts' timers
2190 * To use, set the timer expires field
2191 * and add_timer
2192 */
2193 init_timer(&hd->timer);
2194 hd->timer.data = (unsigned long) hd;
2195 hd->timer.function = mptscsih_timer_expired;
2196
2197 hd->mpt_pq_filter = mpt_pq_filter;
2198 ioc->sas_data.ptClear = mpt_pt_clear;
2199
2200 if (ioc->sas_data.ptClear==1) {
2201 mptbase_sas_persist_operation(
2202 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2203 }
2204
2205 ddvprintk((MYIOC_s_INFO_FMT
2206 "mpt_pq_filter %x mpt_pq_filter %x\n",
2207 ioc->name,
2208 mpt_pq_filter,
2209 mpt_pq_filter));
2210
2211 init_waitqueue_head(&hd->scandv_waitq);
2212 hd->scandv_wait_done = 0;
2213 hd->last_queue_full = 0;
2214
2215 error = scsi_add_host(sh, &ioc->pcidev->dev);
2216 if (error) {
2217 dprintk((KERN_ERR MYNAM
2218 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002219 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002220 }
2221
2222 mptsas_scan_sas_topology(ioc);
2223
2224 return 0;
2225
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002226out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002227
2228 mptscsih_remove(pdev);
2229 return error;
2230}
2231
2232static void __devexit mptsas_remove(struct pci_dev *pdev)
2233{
2234 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2235 struct mptsas_portinfo *p, *n;
2236
Moore, Erice6b2d762006-03-14 09:14:24 -07002237 ioc->sas_discovery_ignore_events=1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002238 sas_remove_host(ioc->sh);
2239
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002240 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002241 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2242 list_del(&p->list);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002243 if (p->phy_info)
2244 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002245 kfree(p);
2246 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002247 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002248
2249 mptscsih_remove(pdev);
2250}
2251
2252static struct pci_device_id mptsas_pci_table[] = {
2253 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
2254 PCI_ANY_ID, PCI_ANY_ID },
2255 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
2256 PCI_ANY_ID, PCI_ANY_ID },
2257 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
2258 PCI_ANY_ID, PCI_ANY_ID },
2259 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
2260 PCI_ANY_ID, PCI_ANY_ID },
2261 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
2262 PCI_ANY_ID, PCI_ANY_ID },
2263 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
2264 PCI_ANY_ID, PCI_ANY_ID },
2265 {0} /* Terminating entry */
2266};
2267MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2268
2269
2270static struct pci_driver mptsas_driver = {
2271 .name = "mptsas",
2272 .id_table = mptsas_pci_table,
2273 .probe = mptsas_probe,
2274 .remove = __devexit_p(mptsas_remove),
2275 .shutdown = mptscsih_shutdown,
2276#ifdef CONFIG_PM
2277 .suspend = mptscsih_suspend,
2278 .resume = mptscsih_resume,
2279#endif
2280};
2281
2282static int __init
2283mptsas_init(void)
2284{
2285 show_mptmod_ver(my_NAME, my_VERSION);
2286
2287 mptsas_transport_template =
2288 sas_attach_transport(&mptsas_transport_functions);
2289 if (!mptsas_transport_template)
2290 return -ENODEV;
2291
2292 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
2293 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
2294 mptsasInternalCtx =
2295 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002296 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002297
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002298 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07002299 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002300 ": Registered for IOC event notifications\n"));
2301 }
2302
2303 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
2304 dprintk((KERN_INFO MYNAM
2305 ": Registered for IOC reset notifications\n"));
2306 }
2307
2308 return pci_register_driver(&mptsas_driver);
2309}
2310
2311static void __exit
2312mptsas_exit(void)
2313{
2314 pci_unregister_driver(&mptsas_driver);
2315 sas_release_transport(mptsas_transport_template);
2316
2317 mpt_reset_deregister(mptsasDoneCtx);
2318 mpt_event_deregister(mptsasDoneCtx);
2319
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002320 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002321 mpt_deregister(mptsasInternalCtx);
2322 mpt_deregister(mptsasTaskCtx);
2323 mpt_deregister(mptsasDoneCtx);
2324}
2325
2326module_init(mptsas_init);
2327module_exit(mptsas_exit);