blob: 010d4a39269b8c55dc39eab53516f4a68636f44c [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
James Bottomleyf013db32006-03-18 14:54:36 -0600366static int
367mptsas_slave_configure(struct scsi_device *sdev)
368{
369 sas_read_port_mode_page(sdev);
370
371 return mptscsih_slave_configure(sdev);
372}
373
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200374/*
375 * This is pretty ugly. We will be able to seriously clean it up
376 * once the DV code in mptscsih goes away and we can properly
377 * implement ->target_alloc.
378 */
379static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700380mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200381{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700382 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200383 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
384 struct sas_rphy *rphy;
385 struct mptsas_portinfo *p;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700386 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200387 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700388 struct scsi_target *starget;
Moore, Eric914c2d82006-03-14 09:19:36 -0700389 u32 target_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200390 int i;
391
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100392 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200393 if (!vdev) {
394 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
395 hd->ioc->name, sizeof(VirtDevice));
396 return -ENOMEM;
397 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700398 sdev->hostdata = vdev;
399 starget = scsi_target(sdev);
400 vtarget = starget->hostdata;
Moore, Eric914c2d82006-03-14 09:19:36 -0700401 vtarget->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700402 vdev->vtarget = vtarget;
403 if (vtarget->num_luns == 0) {
404 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
405 hd->Targets[sdev->id] = vtarget;
406 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200407
Moore, Eric816aa902006-01-13 16:25:20 -0700408 /*
409 RAID volumes placed beyond the last expected port.
410 */
411 if (sdev->channel == hd->ioc->num_ports) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700412 target_id = sdev->id;
413 vtarget->bus_id = 0;
Moore, Eric816aa902006-01-13 16:25:20 -0700414 vdev->lun = 0;
415 goto out;
416 }
417
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700418 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100419 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200420 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
421 for (i = 0; i < p->num_phys; i++) {
422 if (p->phy_info[i].attached.sas_address ==
423 rphy->identify.sas_address) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700424 target_id = p->phy_info[i].attached.id;
425 vtarget->bus_id = p->phy_info[i].attached.channel;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700426 vdev->lun = sdev->lun;
Moore, Ericf44e5462006-03-14 09:14:21 -0700427 p->phy_info[i].starget = sdev->sdev_target;
428 /*
429 * Exposing hidden disk (RAID)
430 */
431 if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
432 target_id = mptscsih_raid_id_to_num(hd,
433 target_id);
434 vdev->vtarget->tflags |=
435 MPT_TARGET_FLAGS_RAID_COMPONENT;
436 sdev->no_uld_attach = 1;
437 }
Moore, Eric914c2d82006-03-14 09:19:36 -0700438 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200439 goto out;
440 }
441 }
442 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100443 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200444
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200445 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100446 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200447
448 out:
Moore, Eric914c2d82006-03-14 09:19:36 -0700449 vtarget->target_id = target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700450 vtarget->num_luns++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200451 return 0;
452}
453
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100454static void
455mptsas_slave_destroy(struct scsi_device *sdev)
456{
457 struct Scsi_Host *host = sdev->host;
458 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700459 VirtDevice *vdev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100460
461 /*
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700462 * Issue target reset to flush firmware outstanding commands.
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100463 */
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700464 vdev = sdev->hostdata;
465 if (vdev->configured_lun){
466 if (mptscsih_TMHandler(hd,
467 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -0700468 vdev->vtarget->bus_id,
469 vdev->vtarget->target_id,
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700470 0, 0, 5 /* 5 second timeout */)
471 < 0){
472
473 /* The TM request failed!
474 * Fatal error case.
475 */
476 printk(MYIOC_s_WARN_FMT
477 "Error processing TaskMgmt id=%d TARGET_RESET\n",
478 hd->ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700479 vdev->vtarget->target_id);
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700480
481 hd->tmPending = 0;
482 hd->tmState = TM_STATE_NONE;
483 }
484 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100485 mptscsih_slave_destroy(sdev);
486}
487
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200488static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700489 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200490 .proc_name = "mptsas",
491 .proc_info = mptscsih_proc_info,
492 .name = "MPT SPI Host",
493 .info = mptscsih_info,
494 .queuecommand = mptscsih_qcmd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700495 .target_alloc = mptscsih_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200496 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -0600497 .slave_configure = mptsas_slave_configure,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700498 .target_destroy = mptscsih_target_destroy,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100499 .slave_destroy = mptsas_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200500 .change_queue_depth = mptscsih_change_queue_depth,
501 .eh_abort_handler = mptscsih_abort,
502 .eh_device_reset_handler = mptscsih_dev_reset,
503 .eh_bus_reset_handler = mptscsih_bus_reset,
504 .eh_host_reset_handler = mptscsih_host_reset,
505 .bios_param = mptscsih_bios_param,
506 .can_queue = MPT_FC_CAN_QUEUE,
507 .this_id = -1,
508 .sg_tablesize = MPT_SCSI_SG_DEPTH,
509 .max_sectors = 8192,
510 .cmd_per_lun = 7,
511 .use_clustering = ENABLE_CLUSTERING,
512};
513
Christoph Hellwigb5141122005-10-28 22:07:41 +0200514static int mptsas_get_linkerrors(struct sas_phy *phy)
515{
516 MPT_ADAPTER *ioc = phy_to_ioc(phy);
517 ConfigExtendedPageHeader_t hdr;
518 CONFIGPARMS cfg;
519 SasPhyPage1_t *buffer;
520 dma_addr_t dma_handle;
521 int error;
522
523 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
524 hdr.ExtPageLength = 0;
525 hdr.PageNumber = 1 /* page number 1*/;
526 hdr.Reserved1 = 0;
527 hdr.Reserved2 = 0;
528 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
529 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
530
531 cfg.cfghdr.ehdr = &hdr;
532 cfg.physAddr = -1;
533 cfg.pageAddr = phy->identify.phy_identifier;
534 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
535 cfg.dir = 0; /* read */
536 cfg.timeout = 10;
537
538 error = mpt_config(ioc, &cfg);
539 if (error)
540 return error;
541 if (!hdr.ExtPageLength)
542 return -ENXIO;
543
544 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
545 &dma_handle);
546 if (!buffer)
547 return -ENOMEM;
548
549 cfg.physAddr = dma_handle;
550 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
551
552 error = mpt_config(ioc, &cfg);
553 if (error)
554 goto out_free_consistent;
555
556 mptsas_print_phy_pg1(buffer);
557
558 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
559 phy->running_disparity_error_count =
560 le32_to_cpu(buffer->RunningDisparityErrorCount);
561 phy->loss_of_dword_sync_count =
562 le32_to_cpu(buffer->LossDwordSynchCount);
563 phy->phy_reset_problem_count =
564 le32_to_cpu(buffer->PhyResetProblemCount);
565
566 out_free_consistent:
567 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
568 buffer, dma_handle);
569 return error;
570}
571
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200572static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
573 MPT_FRAME_HDR *reply)
574{
575 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
576 if (reply != NULL) {
577 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
578 memcpy(ioc->sas_mgmt.reply, reply,
579 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
580 }
581 complete(&ioc->sas_mgmt.done);
582 return 1;
583}
584
585static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
586{
587 MPT_ADAPTER *ioc = phy_to_ioc(phy);
588 SasIoUnitControlRequest_t *req;
589 SasIoUnitControlReply_t *reply;
590 MPT_FRAME_HDR *mf;
591 MPIHeader_t *hdr;
592 unsigned long timeleft;
593 int error = -ERESTARTSYS;
594
595 /* not implemented for expanders */
596 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
597 return -ENXIO;
598
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100599 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200600 goto out;
601
602 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
603 if (!mf) {
604 error = -ENOMEM;
605 goto out_unlock;
606 }
607
608 hdr = (MPIHeader_t *) mf;
609 req = (SasIoUnitControlRequest_t *)mf;
610 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
611 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
612 req->MsgContext = hdr->MsgContext;
613 req->Operation = hard_reset ?
614 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
615 req->PhyNum = phy->identify.phy_identifier;
616
617 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
618
619 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
620 10 * HZ);
621 if (!timeleft) {
622 /* On timeout reset the board */
623 mpt_free_msg_frame(ioc, mf);
624 mpt_HardResetHandler(ioc, CAN_SLEEP);
625 error = -ETIMEDOUT;
626 goto out_unlock;
627 }
628
629 /* a reply frame is expected */
630 if ((ioc->sas_mgmt.status &
631 MPT_IOCTL_STATUS_RF_VALID) == 0) {
632 error = -ENXIO;
633 goto out_unlock;
634 }
635
636 /* process the completed Reply Message Frame */
637 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
638 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
639 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
640 __FUNCTION__,
641 reply->IOCStatus,
642 reply->IOCLogInfo);
643 error = -ENXIO;
644 goto out_unlock;
645 }
646
647 error = 0;
648
649 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100650 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200651 out:
652 return error;
653}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200654
Christoph Hellwige3094442006-02-16 13:25:36 +0100655static int
656mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
657{
658 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
659 int i, error;
660 struct mptsas_portinfo *p;
661 struct mptsas_enclosure enclosure_info;
662 u64 enclosure_handle;
663
664 mutex_lock(&ioc->sas_topology_mutex);
665 list_for_each_entry(p, &ioc->sas_topology, list) {
666 for (i = 0; i < p->num_phys; i++) {
667 if (p->phy_info[i].attached.sas_address ==
668 rphy->identify.sas_address) {
669 enclosure_handle = p->phy_info[i].
670 attached.handle_enclosure;
671 goto found_info;
672 }
673 }
674 }
675 mutex_unlock(&ioc->sas_topology_mutex);
676 return -ENXIO;
677
678 found_info:
679 mutex_unlock(&ioc->sas_topology_mutex);
680 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -0700681 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +0100682 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
683 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
684 if (!error)
685 *identifier = enclosure_info.enclosure_logical_id;
686 return error;
687}
688
689static int
690mptsas_get_bay_identifier(struct sas_rphy *rphy)
691{
692 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
693 struct mptsas_portinfo *p;
694 int i, rc;
695
696 mutex_lock(&ioc->sas_topology_mutex);
697 list_for_each_entry(p, &ioc->sas_topology, list) {
698 for (i = 0; i < p->num_phys; i++) {
699 if (p->phy_info[i].attached.sas_address ==
700 rphy->identify.sas_address) {
701 rc = p->phy_info[i].attached.slot;
702 goto out;
703 }
704 }
705 }
706 rc = -ENXIO;
707 out:
708 mutex_unlock(&ioc->sas_topology_mutex);
709 return rc;
710}
711
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200712static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +0200713 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +0100714 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
715 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200716 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200717};
718
719static struct scsi_transport_template *mptsas_transport_template;
720
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200721static int
722mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
723{
724 ConfigExtendedPageHeader_t hdr;
725 CONFIGPARMS cfg;
726 SasIOUnitPage0_t *buffer;
727 dma_addr_t dma_handle;
728 int error, i;
729
730 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
731 hdr.ExtPageLength = 0;
732 hdr.PageNumber = 0;
733 hdr.Reserved1 = 0;
734 hdr.Reserved2 = 0;
735 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
736 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
737
738 cfg.cfghdr.ehdr = &hdr;
739 cfg.physAddr = -1;
740 cfg.pageAddr = 0;
741 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
742 cfg.dir = 0; /* read */
743 cfg.timeout = 10;
744
745 error = mpt_config(ioc, &cfg);
746 if (error)
747 goto out;
748 if (!hdr.ExtPageLength) {
749 error = -ENXIO;
750 goto out;
751 }
752
753 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
754 &dma_handle);
755 if (!buffer) {
756 error = -ENOMEM;
757 goto out;
758 }
759
760 cfg.physAddr = dma_handle;
761 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
762
763 error = mpt_config(ioc, &cfg);
764 if (error)
765 goto out_free_consistent;
766
767 port_info->num_phys = buffer->NumPhys;
768 port_info->phy_info = kcalloc(port_info->num_phys,
769 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
770 if (!port_info->phy_info) {
771 error = -ENOMEM;
772 goto out_free_consistent;
773 }
774
Moore, Ericdb9c9172006-03-14 09:14:18 -0700775 if (port_info->num_phys)
776 port_info->handle =
777 le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200778 for (i = 0; i < port_info->num_phys; i++) {
779 mptsas_print_phy_data(&buffer->PhyData[i]);
780 port_info->phy_info[i].phy_id = i;
781 port_info->phy_info[i].port_id =
782 buffer->PhyData[i].Port;
783 port_info->phy_info[i].negotiated_link_rate =
784 buffer->PhyData[i].NegotiatedLinkRate;
785 }
786
787 out_free_consistent:
788 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
789 buffer, dma_handle);
790 out:
791 return error;
792}
793
794static int
795mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
796 u32 form, u32 form_specific)
797{
798 ConfigExtendedPageHeader_t hdr;
799 CONFIGPARMS cfg;
800 SasPhyPage0_t *buffer;
801 dma_addr_t dma_handle;
802 int error;
803
804 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
805 hdr.ExtPageLength = 0;
806 hdr.PageNumber = 0;
807 hdr.Reserved1 = 0;
808 hdr.Reserved2 = 0;
809 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
810 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
811
812 cfg.cfghdr.ehdr = &hdr;
813 cfg.dir = 0; /* read */
814 cfg.timeout = 10;
815
816 /* Get Phy Pg 0 for each Phy. */
817 cfg.physAddr = -1;
818 cfg.pageAddr = form + form_specific;
819 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
820
821 error = mpt_config(ioc, &cfg);
822 if (error)
823 goto out;
824
825 if (!hdr.ExtPageLength) {
826 error = -ENXIO;
827 goto out;
828 }
829
830 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
831 &dma_handle);
832 if (!buffer) {
833 error = -ENOMEM;
834 goto out;
835 }
836
837 cfg.physAddr = dma_handle;
838 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
839
840 error = mpt_config(ioc, &cfg);
841 if (error)
842 goto out_free_consistent;
843
844 mptsas_print_phy_pg0(buffer);
845
846 phy_info->hw_link_rate = buffer->HwLinkRate;
847 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
848 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
849 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
850
851 out_free_consistent:
852 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
853 buffer, dma_handle);
854 out:
855 return error;
856}
857
858static int
859mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
860 u32 form, u32 form_specific)
861{
862 ConfigExtendedPageHeader_t hdr;
863 CONFIGPARMS cfg;
864 SasDevicePage0_t *buffer;
865 dma_addr_t dma_handle;
866 __le64 sas_address;
867 int error;
868
869 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
870 hdr.ExtPageLength = 0;
871 hdr.PageNumber = 0;
872 hdr.Reserved1 = 0;
873 hdr.Reserved2 = 0;
874 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
875 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
876
877 cfg.cfghdr.ehdr = &hdr;
878 cfg.pageAddr = form + form_specific;
879 cfg.physAddr = -1;
880 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
881 cfg.dir = 0; /* read */
882 cfg.timeout = 10;
883
Moore, Ericdb9c9172006-03-14 09:14:18 -0700884 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200885 error = mpt_config(ioc, &cfg);
886 if (error)
887 goto out;
888 if (!hdr.ExtPageLength) {
889 error = -ENXIO;
890 goto out;
891 }
892
893 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
894 &dma_handle);
895 if (!buffer) {
896 error = -ENOMEM;
897 goto out;
898 }
899
900 cfg.physAddr = dma_handle;
901 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
902
903 error = mpt_config(ioc, &cfg);
904 if (error)
905 goto out_free_consistent;
906
907 mptsas_print_device_pg0(buffer);
908
909 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -0700910 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +0100911 device_info->handle_enclosure =
912 le16_to_cpu(buffer->EnclosureHandle);
913 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200914 device_info->phy_id = buffer->PhyNum;
915 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100916 device_info->id = buffer->TargetID;
917 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200918 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
919 device_info->sas_address = le64_to_cpu(sas_address);
920 device_info->device_info =
921 le32_to_cpu(buffer->DeviceInfo);
922
923 out_free_consistent:
924 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
925 buffer, dma_handle);
926 out:
927 return error;
928}
929
930static int
931mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
932 u32 form, u32 form_specific)
933{
934 ConfigExtendedPageHeader_t hdr;
935 CONFIGPARMS cfg;
936 SasExpanderPage0_t *buffer;
937 dma_addr_t dma_handle;
938 int error;
939
940 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
941 hdr.ExtPageLength = 0;
942 hdr.PageNumber = 0;
943 hdr.Reserved1 = 0;
944 hdr.Reserved2 = 0;
945 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
946 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
947
948 cfg.cfghdr.ehdr = &hdr;
949 cfg.physAddr = -1;
950 cfg.pageAddr = form + form_specific;
951 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
952 cfg.dir = 0; /* read */
953 cfg.timeout = 10;
954
Moore, Ericdb9c9172006-03-14 09:14:18 -0700955 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200956 error = mpt_config(ioc, &cfg);
957 if (error)
958 goto out;
959
960 if (!hdr.ExtPageLength) {
961 error = -ENXIO;
962 goto out;
963 }
964
965 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
966 &dma_handle);
967 if (!buffer) {
968 error = -ENOMEM;
969 goto out;
970 }
971
972 cfg.physAddr = dma_handle;
973 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
974
975 error = mpt_config(ioc, &cfg);
976 if (error)
977 goto out_free_consistent;
978
979 /* save config data */
980 port_info->num_phys = buffer->NumPhys;
981 port_info->handle = le16_to_cpu(buffer->DevHandle);
982 port_info->phy_info = kcalloc(port_info->num_phys,
983 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
984 if (!port_info->phy_info) {
985 error = -ENOMEM;
986 goto out_free_consistent;
987 }
988
989 out_free_consistent:
990 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
991 buffer, dma_handle);
992 out:
993 return error;
994}
995
996static int
997mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
998 u32 form, u32 form_specific)
999{
1000 ConfigExtendedPageHeader_t hdr;
1001 CONFIGPARMS cfg;
1002 SasExpanderPage1_t *buffer;
1003 dma_addr_t dma_handle;
1004 int error;
1005
1006 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1007 hdr.ExtPageLength = 0;
1008 hdr.PageNumber = 1;
1009 hdr.Reserved1 = 0;
1010 hdr.Reserved2 = 0;
1011 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1012 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1013
1014 cfg.cfghdr.ehdr = &hdr;
1015 cfg.physAddr = -1;
1016 cfg.pageAddr = form + form_specific;
1017 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1018 cfg.dir = 0; /* read */
1019 cfg.timeout = 10;
1020
1021 error = mpt_config(ioc, &cfg);
1022 if (error)
1023 goto out;
1024
1025 if (!hdr.ExtPageLength) {
1026 error = -ENXIO;
1027 goto out;
1028 }
1029
1030 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1031 &dma_handle);
1032 if (!buffer) {
1033 error = -ENOMEM;
1034 goto out;
1035 }
1036
1037 cfg.physAddr = dma_handle;
1038 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1039
1040 error = mpt_config(ioc, &cfg);
1041 if (error)
1042 goto out_free_consistent;
1043
1044
1045 mptsas_print_expander_pg1(buffer);
1046
1047 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001048 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001049 phy_info->port_id = buffer->PhysicalPort;
1050 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1051 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1052 phy_info->hw_link_rate = buffer->HwLinkRate;
1053 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1054 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1055
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001056 out_free_consistent:
1057 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1058 buffer, dma_handle);
1059 out:
1060 return error;
1061}
1062
Moore, Ericc73787ee2006-01-26 16:20:06 -07001063/*
1064 * Returns true if there is a scsi end device
1065 */
1066static inline int
1067mptsas_is_end_device(struct mptsas_devinfo * attached)
1068{
1069 if ((attached->handle) &&
1070 (attached->device_info &
1071 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
1072 ((attached->device_info &
1073 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1074 (attached->device_info &
1075 MPI_SAS_DEVICE_INFO_STP_TARGET) |
1076 (attached->device_info &
1077 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
1078 return 1;
1079 else
1080 return 0;
1081}
1082
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001083static void
1084mptsas_parse_device_info(struct sas_identify *identify,
1085 struct mptsas_devinfo *device_info)
1086{
1087 u16 protocols;
1088
1089 identify->sas_address = device_info->sas_address;
1090 identify->phy_identifier = device_info->phy_id;
1091
1092 /*
1093 * Fill in Phy Initiator Port Protocol.
1094 * Bits 6:3, more than one bit can be set, fall through cases.
1095 */
1096 protocols = device_info->device_info & 0x78;
1097 identify->initiator_port_protocols = 0;
1098 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1099 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1100 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1101 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1102 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1103 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1104 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1105 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1106
1107 /*
1108 * Fill in Phy Target Port Protocol.
1109 * Bits 10:7, more than one bit can be set, fall through cases.
1110 */
1111 protocols = device_info->device_info & 0x780;
1112 identify->target_port_protocols = 0;
1113 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1114 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1115 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1116 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1117 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1118 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1119 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1120 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1121
1122 /*
1123 * Fill in Attached device type.
1124 */
1125 switch (device_info->device_info &
1126 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1127 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1128 identify->device_type = SAS_PHY_UNUSED;
1129 break;
1130 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1131 identify->device_type = SAS_END_DEVICE;
1132 break;
1133 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1134 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1135 break;
1136 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1137 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1138 break;
1139 }
1140}
1141
1142static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001143 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001144{
Moore, Erice6b2d762006-03-14 09:14:24 -07001145 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001146 struct sas_phy *phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001147 int error;
1148
Moore, Erice6b2d762006-03-14 09:14:24 -07001149 if (!dev)
1150 return -ENODEV;
1151
1152 if (!phy_info->phy) {
1153 phy = sas_phy_alloc(dev, index);
1154 if (!phy)
1155 return -ENOMEM;
1156 } else
1157 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001158
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001159 phy->port_identifier = phy_info->port_id;
1160 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001161
1162 /*
1163 * Set Negotiated link rate.
1164 */
1165 switch (phy_info->negotiated_link_rate) {
1166 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001167 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001168 break;
1169 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001170 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001171 break;
1172 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001173 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001174 break;
1175 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001176 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001177 break;
1178 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1179 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1180 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001181 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001182 break;
1183 }
1184
1185 /*
1186 * Set Max hardware link rate.
1187 */
1188 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1189 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001190 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001191 break;
1192 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001193 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001194 break;
1195 default:
1196 break;
1197 }
1198
1199 /*
1200 * Set Max programmed link rate.
1201 */
1202 switch (phy_info->programmed_link_rate &
1203 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1204 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001205 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001206 break;
1207 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001208 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001209 break;
1210 default:
1211 break;
1212 }
1213
1214 /*
1215 * Set Min hardware link rate.
1216 */
1217 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1218 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001219 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001220 break;
1221 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001222 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001223 break;
1224 default:
1225 break;
1226 }
1227
1228 /*
1229 * Set Min programmed link rate.
1230 */
1231 switch (phy_info->programmed_link_rate &
1232 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1233 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001234 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001235 break;
1236 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001237 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001238 break;
1239 default:
1240 break;
1241 }
1242
Moore, Erice6b2d762006-03-14 09:14:24 -07001243 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001244
Moore, Erice6b2d762006-03-14 09:14:24 -07001245 if (local)
1246 phy->local_attached = 1;
1247
1248 error = sas_phy_add(phy);
1249 if (error) {
1250 sas_phy_free(phy);
1251 return error;
1252 }
1253 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001254 }
1255
Moore, Erice6b2d762006-03-14 09:14:24 -07001256 if ((phy_info->attached.handle) &&
1257 (!phy_info->rphy)) {
1258
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001259 struct sas_rphy *rphy;
James Bottomleyf013db32006-03-18 14:54:36 -06001260 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001261
Moore, Erice6b2d762006-03-14 09:14:24 -07001262 ioc = phy_to_ioc(phy_info->phy);
1263
1264 /*
1265 * Let the hotplug_work thread handle processing
1266 * the adding/removing of devices that occur
1267 * after start of day.
1268 */
1269 if (ioc->sas_discovery_runtime &&
1270 mptsas_is_end_device(&phy_info->attached))
1271 return 0;
1272
James Bottomleyf013db32006-03-18 14:54:36 -06001273 mptsas_parse_device_info(&identify, &phy_info->attached);
1274 switch (identify.device_type) {
1275 case SAS_END_DEVICE:
1276 rphy = sas_end_device_alloc(phy);
1277 break;
1278 case SAS_EDGE_EXPANDER_DEVICE:
1279 case SAS_FANOUT_EXPANDER_DEVICE:
1280 rphy = sas_expander_alloc(phy, identify.device_type);
1281 break;
1282 default:
1283 rphy = NULL;
1284 break;
1285 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001286 if (!rphy)
1287 return 0; /* non-fatal: an rphy can be added later */
1288
James Bottomleyf013db32006-03-18 14:54:36 -06001289 rphy->identify = identify;
1290
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001291 error = sas_rphy_add(rphy);
1292 if (error) {
1293 sas_rphy_free(rphy);
1294 return error;
1295 }
1296
1297 phy_info->rphy = rphy;
1298 }
1299
1300 return 0;
1301}
1302
1303static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001304mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001305{
Moore, Erice6b2d762006-03-14 09:14:24 -07001306 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001307 u32 handle = 0xFFFF;
1308 int error = -ENOMEM, i;
1309
Moore, Erice6b2d762006-03-14 09:14:24 -07001310 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1311 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001312 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001313
Moore, Erice6b2d762006-03-14 09:14:24 -07001314 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001315 if (error)
1316 goto out_free_port_info;
1317
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001318 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001319 port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
1320 if (!port_info) {
1321 port_info = hba;
1322 list_add_tail(&port_info->list, &ioc->sas_topology);
1323 } else {
1324 port_info->handle = hba->handle;
1325 for (i = 0; i < hba->num_phys; i++)
1326 port_info->phy_info[i].negotiated_link_rate =
1327 hba->phy_info[i].negotiated_link_rate;
1328 if (hba->phy_info)
1329 kfree(hba->phy_info);
1330 kfree(hba);
1331 hba = NULL;
1332 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001333 mutex_unlock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001334 ioc->num_ports = port_info->num_phys;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001335
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001336 for (i = 0; i < port_info->num_phys; i++) {
1337 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1338 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1339 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1340
1341 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1342 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1343 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001344 port_info->phy_info[i].identify.phy_id =
1345 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001346 handle = port_info->phy_info[i].identify.handle;
1347
1348 if (port_info->phy_info[i].attached.handle) {
1349 mptsas_sas_device_pg0(ioc,
1350 &port_info->phy_info[i].attached,
1351 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1352 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1353 port_info->phy_info[i].attached.handle);
1354 }
1355
1356 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07001357 &port_info->phy_info[i], ioc->sas_index, 1);
1358 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001359 }
1360
1361 return 0;
1362
1363 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001364 if (hba)
1365 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001366 out:
1367 return error;
1368}
1369
1370static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001371mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001372{
Moore, Erice6b2d762006-03-14 09:14:24 -07001373 struct mptsas_portinfo *port_info, *p, *ex;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001374 int error = -ENOMEM, i, j;
1375
Moore, Erice6b2d762006-03-14 09:14:24 -07001376 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1377 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001378 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001379
Moore, Erice6b2d762006-03-14 09:14:24 -07001380 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001381 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1382 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1383 if (error)
1384 goto out_free_port_info;
1385
Moore, Erice6b2d762006-03-14 09:14:24 -07001386 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001387
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001388 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001389 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1390 if (!port_info) {
1391 port_info = ex;
1392 list_add_tail(&port_info->list, &ioc->sas_topology);
1393 } else {
1394 port_info->handle = ex->handle;
1395 if (ex->phy_info)
1396 kfree(ex->phy_info);
1397 kfree(ex);
1398 ex = NULL;
1399 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001400 mutex_unlock(&ioc->sas_topology_mutex);
1401
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001402 for (i = 0; i < port_info->num_phys; i++) {
1403 struct device *parent;
1404
1405 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1406 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1407 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1408
1409 if (port_info->phy_info[i].identify.handle) {
1410 mptsas_sas_device_pg0(ioc,
1411 &port_info->phy_info[i].identify,
1412 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1413 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1414 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001415 port_info->phy_info[i].identify.phy_id =
1416 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001417 }
1418
1419 if (port_info->phy_info[i].attached.handle) {
1420 mptsas_sas_device_pg0(ioc,
1421 &port_info->phy_info[i].attached,
1422 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1423 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1424 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001425 port_info->phy_info[i].attached.phy_id =
1426 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001427 }
1428
1429 /*
1430 * If we find a parent port handle this expander is
1431 * attached to another expander, else it hangs of the
1432 * HBA phys.
1433 */
1434 parent = &ioc->sh->shost_gendev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001435 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001436 list_for_each_entry(p, &ioc->sas_topology, list) {
1437 for (j = 0; j < p->num_phys; j++) {
1438 if (port_info->phy_info[i].identify.handle ==
1439 p->phy_info[j].attached.handle)
1440 parent = &p->phy_info[j].rphy->dev;
1441 }
1442 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001443 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001444
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001445 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001446 ioc->sas_index, 0);
1447 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001448 }
1449
1450 return 0;
1451
1452 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001453 if (ex) {
1454 if (ex->phy_info)
1455 kfree(ex->phy_info);
1456 kfree(ex);
1457 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001458 out:
1459 return error;
1460}
1461
Moore, Erice6b2d762006-03-14 09:14:24 -07001462/*
1463 * mptsas_delete_expander_phys
1464 *
1465 *
1466 * This will traverse topology, and remove expanders
1467 * that are no longer present
1468 */
1469static void
1470mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1471{
1472 struct mptsas_portinfo buffer;
1473 struct mptsas_portinfo *port_info, *n, *parent;
1474 int i;
1475
1476 mutex_lock(&ioc->sas_topology_mutex);
1477 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1478
1479 if (port_info->phy_info &&
1480 (!(port_info->phy_info[0].identify.device_info &
1481 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1482 continue;
1483
1484 if (mptsas_sas_expander_pg0(ioc, &buffer,
1485 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1486 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1487
1488 /*
1489 * Obtain the port_info instance to the parent port
1490 */
1491 parent = mptsas_find_portinfo_by_handle(ioc,
1492 port_info->phy_info[0].identify.handle_parent);
1493
1494 if (!parent)
1495 goto next_port;
1496
1497 /*
1498 * Delete rphys in the parent that point
1499 * to this expander. The transport layer will
1500 * cleanup all the children.
1501 */
1502 for (i = 0; i < parent->num_phys; i++) {
1503 if ((!parent->phy_info[i].rphy) ||
1504 (parent->phy_info[i].attached.sas_address !=
1505 port_info->phy_info[i].identify.sas_address))
1506 continue;
1507 sas_rphy_delete(parent->phy_info[i].rphy);
1508 memset(&parent->phy_info[i].attached, 0,
1509 sizeof(struct mptsas_devinfo));
1510 parent->phy_info[i].rphy = NULL;
1511 parent->phy_info[i].starget = NULL;
1512 }
1513 next_port:
1514 list_del(&port_info->list);
1515 if (port_info->phy_info)
1516 kfree(port_info->phy_info);
1517 kfree(port_info);
1518 }
1519 /*
1520 * Free this memory allocated from inside
1521 * mptsas_sas_expander_pg0
1522 */
1523 if (buffer.phy_info)
1524 kfree(buffer.phy_info);
1525 }
1526 mutex_unlock(&ioc->sas_topology_mutex);
1527}
1528
1529/*
1530 * Start of day discovery
1531 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001532static void
1533mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1534{
1535 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001536 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001537
Moore, Erice6b2d762006-03-14 09:14:24 -07001538 mutex_lock(&ioc->sas_discovery_mutex);
1539 mptsas_probe_hba_phys(ioc);
1540 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001541 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001542 /*
1543 Reporting RAID volumes.
1544 */
1545 if (!ioc->raid_data.pIocPg2)
1546 goto out;
1547 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1548 goto out;
1549 for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1550 scsi_add_device(ioc->sh, ioc->num_ports,
1551 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
1552 }
1553 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07001554 mutex_unlock(&ioc->sas_discovery_mutex);
1555}
1556
1557/*
1558 * Work queue thread to handle Runtime discovery
1559 * Mere purpose is the hot add/delete of expanders
1560 */
1561static void
1562mptscsih_discovery_work(void * arg)
1563{
1564 struct mptsas_discovery_event *ev = arg;
1565 MPT_ADAPTER *ioc = ev->ioc;
1566 u32 handle = 0xFFFF;
1567
1568 mutex_lock(&ioc->sas_discovery_mutex);
1569 ioc->sas_discovery_runtime=1;
1570 mptsas_delete_expander_phys(ioc);
1571 mptsas_probe_hba_phys(ioc);
1572 while (!mptsas_probe_expander_phys(ioc, &handle))
1573 ;
1574 kfree(ev);
1575 ioc->sas_discovery_runtime=0;
1576 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001577}
1578
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001579static struct mptsas_phyinfo *
1580mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
1581{
1582 struct mptsas_portinfo *port_info;
1583 struct mptsas_devinfo device_info;
1584 struct mptsas_phyinfo *phy_info = NULL;
1585 int i, error;
1586
1587 /*
1588 * Retrieve the parent sas_address
1589 */
1590 error = mptsas_sas_device_pg0(ioc, &device_info,
1591 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1592 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1593 parent_handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001594 if (error)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001595 return NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001596
1597 /*
1598 * The phy_info structures are never deallocated during lifetime of
1599 * a host, so the code below is safe without additional refcounting.
1600 */
1601 mutex_lock(&ioc->sas_topology_mutex);
1602 list_for_each_entry(port_info, &ioc->sas_topology, list) {
1603 for (i = 0; i < port_info->num_phys; i++) {
1604 if (port_info->phy_info[i].identify.sas_address ==
1605 device_info.sas_address &&
1606 port_info->phy_info[i].phy_id == phy_id) {
1607 phy_info = &port_info->phy_info[i];
1608 break;
1609 }
1610 }
1611 }
1612 mutex_unlock(&ioc->sas_topology_mutex);
1613
1614 return phy_info;
1615}
1616
1617static struct mptsas_phyinfo *
Moore, Ericc73787ee2006-01-26 16:20:06 -07001618mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001619{
1620 struct mptsas_portinfo *port_info;
1621 struct mptsas_phyinfo *phy_info = NULL;
1622 int i;
1623
1624 /*
1625 * The phy_info structures are never deallocated during lifetime of
1626 * a host, so the code below is safe without additional refcounting.
1627 */
1628 mutex_lock(&ioc->sas_topology_mutex);
1629 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Moore, Ericc73787ee2006-01-26 16:20:06 -07001630 for (i = 0; i < port_info->num_phys; i++)
1631 if (mptsas_is_end_device(&port_info->phy_info[i].attached))
1632 if (port_info->phy_info[i].attached.id == id) {
1633 phy_info = &port_info->phy_info[i];
1634 break;
1635 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001636 }
1637 mutex_unlock(&ioc->sas_topology_mutex);
1638
1639 return phy_info;
1640}
1641
Moore, Eric4b766472006-03-14 09:14:12 -07001642/*
1643 * Work queue thread to clear the persitency table
1644 */
1645static void
1646mptscsih_sas_persist_clear_table(void * arg)
1647{
1648 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
1649
1650 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
1651}
1652
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001653static void
Moore, Ericf44e5462006-03-14 09:14:21 -07001654mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
1655{
1656 sdev->no_uld_attach = data ? 1 : 0;
1657 scsi_device_reprobe(sdev);
1658}
1659
1660static void
1661mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
1662{
1663 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
1664 mptsas_reprobe_lun);
1665}
1666
Moore, Erice6b2d762006-03-14 09:14:24 -07001667
1668/*
1669 * Work queue thread to handle SAS hotplug events
1670 */
Moore, Ericf44e5462006-03-14 09:14:21 -07001671static void
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001672mptsas_hotplug_work(void *arg)
1673{
1674 struct mptsas_hotplug_event *ev = arg;
1675 MPT_ADAPTER *ioc = ev->ioc;
1676 struct mptsas_phyinfo *phy_info;
1677 struct sas_rphy *rphy;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001678 struct scsi_device *sdev;
James Bottomleyf013db32006-03-18 14:54:36 -06001679 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001680 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001681 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07001682 VirtTarget *vtarget;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001683
Moore, Erice6b2d762006-03-14 09:14:24 -07001684 mutex_lock(&ioc->sas_discovery_mutex);
1685
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001686 switch (ev->event_type) {
1687 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001688
Moore, Ericc73787ee2006-01-26 16:20:06 -07001689 phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001690
Moore, Ericf44e5462006-03-14 09:14:21 -07001691 /*
1692 * Sanity checks, for non-existing phys and remote rphys.
1693 */
1694 if (!phy_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001695 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07001696 if (!phy_info->rphy)
1697 break;
1698 if (phy_info->starget) {
1699 vtarget = phy_info->starget->hostdata;
1700
1701 if (!vtarget)
1702 break;
1703 /*
1704 * Handling RAID components
1705 */
1706 if (ev->phys_disk_num_valid) {
1707 vtarget->target_id = ev->phys_disk_num;
1708 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
1709 mptsas_reprobe_target(vtarget->starget, 1);
1710 break;
1711 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001712 }
1713
Moore, Ericc73787ee2006-01-26 16:20:06 -07001714 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1715 ds = "ssp";
1716 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1717 ds = "stp";
1718 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1719 ds = "sata";
1720
1721 printk(MYIOC_s_INFO_FMT
1722 "removing %s device, channel %d, id %d, phy %d\n",
1723 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
1724
Moore, Ericf44e5462006-03-14 09:14:21 -07001725 sas_rphy_delete(phy_info->rphy);
1726 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
1727 phy_info->rphy = NULL;
1728 phy_info->starget = NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001729 break;
1730 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07001731
1732 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01001733 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07001734 */
Christoph Hellwige3094442006-02-16 13:25:36 +01001735 if (mptsas_sas_device_pg0(ioc, &sas_device,
1736 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
1737 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
1738 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001739
1740 phy_info = mptsas_find_phyinfo_by_parent(ioc,
Christoph Hellwige3094442006-02-16 13:25:36 +01001741 sas_device.handle_parent, sas_device.phy_id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001742
1743 if (!phy_info) {
1744 u32 handle = 0xFFFF;
1745
1746 /*
1747 * Its possible when an expander has been hot added
1748 * containing attached devices, the sas firmware
1749 * may send a RC_ADDED event prior to the
1750 * DISCOVERY STOP event. If that occurs, our
1751 * view of the topology in the driver in respect to this
1752 * expander might of not been setup, and we hit this
1753 * condition.
1754 * Therefore, this code kicks off discovery to
1755 * refresh the data.
1756 * Then again, we check whether the parent phy has
1757 * been created.
1758 */
1759 ioc->sas_discovery_runtime=1;
1760 mptsas_delete_expander_phys(ioc);
1761 mptsas_probe_hba_phys(ioc);
1762 while (!mptsas_probe_expander_phys(ioc, &handle))
1763 ;
1764 ioc->sas_discovery_runtime=0;
1765
1766 phy_info = mptsas_find_phyinfo_by_parent(ioc,
1767 sas_device.handle_parent, sas_device.phy_id);
1768 if (!phy_info)
1769 break;
1770 }
1771
Moore, Ericf44e5462006-03-14 09:14:21 -07001772 if (phy_info->starget) {
1773 vtarget = phy_info->starget->hostdata;
1774
1775 if (!vtarget)
1776 break;
1777 /*
1778 * Handling RAID components
1779 */
1780 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1781 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
1782 vtarget->target_id = ev->id;
1783 mptsas_reprobe_target(phy_info->starget, 0);
1784 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001785 break;
1786 }
1787
Moore, Ericf44e5462006-03-14 09:14:21 -07001788 if (phy_info->rphy)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001789 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001790
Christoph Hellwige3094442006-02-16 13:25:36 +01001791 memcpy(&phy_info->attached, &sas_device,
1792 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001793
Moore, Ericc73787ee2006-01-26 16:20:06 -07001794 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1795 ds = "ssp";
1796 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1797 ds = "stp";
1798 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1799 ds = "sata";
1800
1801 printk(MYIOC_s_INFO_FMT
1802 "attaching %s device, channel %d, id %d, phy %d\n",
1803 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
1804
James Bottomleyf013db32006-03-18 14:54:36 -06001805 mptsas_parse_device_info(&identify, &phy_info->attached);
1806 switch (identify.device_type) {
1807 case SAS_END_DEVICE:
1808 rphy = sas_end_device_alloc(phy_info->phy);
1809 break;
1810 case SAS_EDGE_EXPANDER_DEVICE:
1811 case SAS_FANOUT_EXPANDER_DEVICE:
1812 rphy = sas_expander_alloc(phy_info->phy, identify.device_type);
1813 break;
1814 default:
1815 rphy = NULL;
1816 break;
1817 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001818 if (!rphy)
1819 break; /* non-fatal: an rphy can be added later */
1820
James Bottomleyf013db32006-03-18 14:54:36 -06001821 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001822 if (sas_rphy_add(rphy)) {
1823 sas_rphy_free(rphy);
1824 break;
1825 }
1826
1827 phy_info->rphy = rphy;
1828 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001829 case MPTSAS_ADD_RAID:
1830 sdev = scsi_device_lookup(
1831 ioc->sh,
1832 ioc->num_ports,
1833 ev->id,
1834 0);
1835 if (sdev) {
1836 scsi_device_put(sdev);
1837 break;
1838 }
1839 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001840 "attaching raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001841 ioc->name, ioc->num_ports, ev->id);
1842 scsi_add_device(ioc->sh,
1843 ioc->num_ports,
1844 ev->id,
1845 0);
1846 mpt_findImVolumes(ioc);
1847 break;
1848 case MPTSAS_DEL_RAID:
1849 sdev = scsi_device_lookup(
1850 ioc->sh,
1851 ioc->num_ports,
1852 ev->id,
1853 0);
1854 if (!sdev)
1855 break;
1856 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001857 "removing raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001858 ioc->name, ioc->num_ports, ev->id);
1859 scsi_remove_device(sdev);
1860 scsi_device_put(sdev);
1861 mpt_findImVolumes(ioc);
1862 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001863 }
1864
1865 kfree(ev);
Moore, Erice6b2d762006-03-14 09:14:24 -07001866 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001867}
1868
1869static void
1870mptscsih_send_sas_event(MPT_ADAPTER *ioc,
1871 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1872{
1873 struct mptsas_hotplug_event *ev;
1874 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
1875 __le64 sas_address;
1876
1877 if ((device_info &
1878 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
1879 MPI_SAS_DEVICE_INFO_STP_TARGET |
1880 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
1881 return;
1882
Moore, Eric4b766472006-03-14 09:14:12 -07001883 switch (sas_event_data->ReasonCode) {
1884 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
1885 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
1886 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1887 if (!ev) {
1888 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1889 break;
1890 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001891
Moore, Eric4b766472006-03-14 09:14:12 -07001892 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1893 ev->ioc = ioc;
1894 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
1895 ev->parent_handle =
1896 le16_to_cpu(sas_event_data->ParentDevHandle);
1897 ev->channel = sas_event_data->Bus;
1898 ev->id = sas_event_data->TargetID;
1899 ev->phy_id = sas_event_data->PhyNum;
1900 memcpy(&sas_address, &sas_event_data->SASAddress,
1901 sizeof(__le64));
1902 ev->sas_address = le64_to_cpu(sas_address);
1903 ev->device_info = device_info;
1904
1905 if (sas_event_data->ReasonCode &
1906 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
1907 ev->event_type = MPTSAS_ADD_DEVICE;
1908 else
1909 ev->event_type = MPTSAS_DEL_DEVICE;
1910 schedule_work(&ev->work);
1911 break;
1912 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
1913 /*
1914 * Persistent table is full.
1915 */
1916 INIT_WORK(&ioc->mptscsih_persistTask,
1917 mptscsih_sas_persist_clear_table,
1918 (void *)ioc);
1919 schedule_work(&ioc->mptscsih_persistTask);
1920 break;
1921 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
1922 /* TODO */
1923 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
1924 /* TODO */
1925 default:
1926 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001927 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001928}
1929
Moore, Ericc73787ee2006-01-26 16:20:06 -07001930static void
1931mptscsih_send_raid_event(MPT_ADAPTER *ioc,
1932 EVENT_DATA_RAID *raid_event_data)
1933{
1934 struct mptsas_hotplug_event *ev;
1935 RAID_VOL0_STATUS * volumeStatus;
1936
1937 if (ioc->bus_type != SAS)
1938 return;
1939
1940 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1941 if (!ev) {
1942 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1943 return;
1944 }
1945
1946 memset(ev,0,sizeof(struct mptsas_hotplug_event));
1947 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1948 ev->ioc = ioc;
1949 ev->id = raid_event_data->VolumeID;
1950
1951 switch (raid_event_data->ReasonCode) {
1952 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
1953 ev->event_type = MPTSAS_ADD_DEVICE;
1954 break;
1955 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07001956 ioc->raid_data.isRaid = 1;
1957 ev->phys_disk_num_valid = 1;
1958 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001959 ev->event_type = MPTSAS_DEL_DEVICE;
1960 break;
1961 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
1962 ev->event_type = MPTSAS_DEL_RAID;
1963 break;
1964 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
1965 ev->event_type = MPTSAS_ADD_RAID;
1966 break;
1967 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
1968 volumeStatus = (RAID_VOL0_STATUS *) &
1969 raid_event_data->SettingsStatus;
1970 ev->event_type = (volumeStatus->State ==
1971 MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
1972 MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
1973 break;
1974 default:
1975 break;
1976 }
1977 schedule_work(&ev->work);
1978}
1979
Moore, Erice6b2d762006-03-14 09:14:24 -07001980static void
1981mptscsih_send_discovery(MPT_ADAPTER *ioc,
1982 EVENT_DATA_SAS_DISCOVERY *discovery_data)
1983{
1984 struct mptsas_discovery_event *ev;
1985
1986 /*
1987 * DiscoveryStatus
1988 *
1989 * This flag will be non-zero when firmware
1990 * kicks off discovery, and return to zero
1991 * once its completed.
1992 */
1993 if (discovery_data->DiscoveryStatus)
1994 return;
1995
1996 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1997 if (!ev)
1998 return;
1999 memset(ev,0,sizeof(struct mptsas_discovery_event));
2000 INIT_WORK(&ev->work, mptscsih_discovery_work, ev);
2001 ev->ioc = ioc;
2002 schedule_work(&ev->work);
2003};
2004
2005
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002006static int
2007mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2008{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002009 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002010 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2011
2012 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002013 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002014
Moore, Erice6b2d762006-03-14 09:14:24 -07002015 /*
2016 * sas_discovery_ignore_events
2017 *
2018 * This flag is to prevent anymore processing of
2019 * sas events once mptsas_remove function is called.
2020 */
2021 if (ioc->sas_discovery_ignore_events) {
2022 rc = mptscsih_event_process(ioc, reply);
2023 goto out;
2024 }
2025
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002026 switch (event) {
2027 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
2028 mptscsih_send_sas_event(ioc,
2029 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002030 break;
2031 case MPI_EVENT_INTEGRATED_RAID:
2032 mptscsih_send_raid_event(ioc,
2033 (EVENT_DATA_RAID *)reply->Data);
2034 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002035 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2036 INIT_WORK(&ioc->mptscsih_persistTask,
2037 mptscsih_sas_persist_clear_table,
2038 (void *)ioc);
2039 schedule_work(&ioc->mptscsih_persistTask);
2040 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002041 case MPI_EVENT_SAS_DISCOVERY:
Moore, Erice6b2d762006-03-14 09:14:24 -07002042 mptscsih_send_discovery(ioc,
2043 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2044 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002045 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002046 rc = mptscsih_event_process(ioc, reply);
2047 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002048 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002049 out:
2050
2051 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002052}
2053
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002054static int
2055mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2056{
2057 struct Scsi_Host *sh;
2058 MPT_SCSI_HOST *hd;
2059 MPT_ADAPTER *ioc;
2060 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002061 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002062 int numSGE = 0;
2063 int scale;
2064 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002065 int error=0;
2066 int r;
2067
2068 r = mpt_attach(pdev,id);
2069 if (r)
2070 return r;
2071
2072 ioc = pci_get_drvdata(pdev);
2073 ioc->DoneCtx = mptsasDoneCtx;
2074 ioc->TaskCtx = mptsasTaskCtx;
2075 ioc->InternalCtx = mptsasInternalCtx;
2076
2077 /* Added sanity check on readiness of the MPT adapter.
2078 */
2079 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2080 printk(MYIOC_s_WARN_FMT
2081 "Skipping because it's not operational!\n",
2082 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002083 error = -ENODEV;
2084 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085 }
2086
2087 if (!ioc->active) {
2088 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2089 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002090 error = -ENODEV;
2091 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002092 }
2093
2094 /* Sanity check - ensure at least 1 port is INITIATOR capable
2095 */
2096 ioc_cap = 0;
2097 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2098 if (ioc->pfacts[ii].ProtocolFlags &
2099 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2100 ioc_cap++;
2101 }
2102
2103 if (!ioc_cap) {
2104 printk(MYIOC_s_WARN_FMT
2105 "Skipping ioc=%p because SCSI Initiator mode "
2106 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002107 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002108 }
2109
2110 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2111 if (!sh) {
2112 printk(MYIOC_s_WARN_FMT
2113 "Unable to register controller with SCSI subsystem\n",
2114 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002115 error = -1;
2116 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002117 }
2118
2119 spin_lock_irqsave(&ioc->FreeQlock, flags);
2120
2121 /* Attach the SCSI Host to the IOC structure
2122 */
2123 ioc->sh = sh;
2124
2125 sh->io_port = 0;
2126 sh->n_io_port = 0;
2127 sh->irq = 0;
2128
2129 /* set 16 byte cdb's */
2130 sh->max_cmd_len = 16;
2131
2132 sh->max_id = ioc->pfacts->MaxDevices + 1;
2133
2134 sh->transportt = mptsas_transport_template;
2135
2136 sh->max_lun = MPT_LAST_LUN + 1;
2137 sh->max_channel = 0;
2138 sh->this_id = ioc->pfacts[0].PortSCSIID;
2139
2140 /* Required entry.
2141 */
2142 sh->unique_id = ioc->id;
2143
2144 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002145 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002146 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002147 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002148 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002149
2150 /* Verify that we won't exceed the maximum
2151 * number of chain buffers
2152 * We can optimize: ZZ = req_sz/sizeof(SGE)
2153 * For 32bit SGE's:
2154 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2155 * + (req_sz - 64)/sizeof(SGE)
2156 * A slightly different algorithm is required for
2157 * 64bit SGEs.
2158 */
2159 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2160 if (sizeof(dma_addr_t) == sizeof(u64)) {
2161 numSGE = (scale - 1) *
2162 (ioc->facts.MaxChainDepth-1) + scale +
2163 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2164 sizeof(u32));
2165 } else {
2166 numSGE = 1 + (scale - 1) *
2167 (ioc->facts.MaxChainDepth-1) + scale +
2168 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2169 sizeof(u32));
2170 }
2171
2172 if (numSGE < sh->sg_tablesize) {
2173 /* Reset this value */
2174 dprintk((MYIOC_s_INFO_FMT
2175 "Resetting sg_tablesize to %d from %d\n",
2176 ioc->name, numSGE, sh->sg_tablesize));
2177 sh->sg_tablesize = numSGE;
2178 }
2179
2180 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2181
2182 hd = (MPT_SCSI_HOST *) sh->hostdata;
2183 hd->ioc = ioc;
2184
2185 /* SCSI needs scsi_cmnd lookup table!
2186 * (with size equal to req_depth*PtrSz!)
2187 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002188 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2189 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002190 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002191 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002192 }
2193
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002194 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2195 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002196
2197 /* Allocate memory for the device structures.
2198 * A non-Null pointer at an offset
2199 * indicates a device exists.
2200 * max_id = 1 + maximum id (hosts.h)
2201 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002202 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
2203 if (!hd->Targets) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002204 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002205 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002206 }
2207
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002208 dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002209
2210 /* Clear the TM flags
2211 */
2212 hd->tmPending = 0;
2213 hd->tmState = TM_STATE_NONE;
2214 hd->resetPending = 0;
2215 hd->abortSCpnt = NULL;
2216
2217 /* Clear the pointer used to store
2218 * single-threaded commands, i.e., those
2219 * issued during a bus scan, dv and
2220 * configuration pages.
2221 */
2222 hd->cmdPtr = NULL;
2223
2224 /* Initialize this SCSI Hosts' timers
2225 * To use, set the timer expires field
2226 * and add_timer
2227 */
2228 init_timer(&hd->timer);
2229 hd->timer.data = (unsigned long) hd;
2230 hd->timer.function = mptscsih_timer_expired;
2231
2232 hd->mpt_pq_filter = mpt_pq_filter;
2233 ioc->sas_data.ptClear = mpt_pt_clear;
2234
2235 if (ioc->sas_data.ptClear==1) {
2236 mptbase_sas_persist_operation(
2237 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2238 }
2239
2240 ddvprintk((MYIOC_s_INFO_FMT
2241 "mpt_pq_filter %x mpt_pq_filter %x\n",
2242 ioc->name,
2243 mpt_pq_filter,
2244 mpt_pq_filter));
2245
2246 init_waitqueue_head(&hd->scandv_waitq);
2247 hd->scandv_wait_done = 0;
2248 hd->last_queue_full = 0;
2249
2250 error = scsi_add_host(sh, &ioc->pcidev->dev);
2251 if (error) {
2252 dprintk((KERN_ERR MYNAM
2253 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002254 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002255 }
2256
2257 mptsas_scan_sas_topology(ioc);
2258
2259 return 0;
2260
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002261out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002262
2263 mptscsih_remove(pdev);
2264 return error;
2265}
2266
2267static void __devexit mptsas_remove(struct pci_dev *pdev)
2268{
2269 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2270 struct mptsas_portinfo *p, *n;
2271
Moore, Erice6b2d762006-03-14 09:14:24 -07002272 ioc->sas_discovery_ignore_events=1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002273 sas_remove_host(ioc->sh);
2274
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002275 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002276 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2277 list_del(&p->list);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002278 if (p->phy_info)
2279 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002280 kfree(p);
2281 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002282 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283
2284 mptscsih_remove(pdev);
2285}
2286
2287static struct pci_device_id mptsas_pci_table[] = {
2288 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
2289 PCI_ANY_ID, PCI_ANY_ID },
2290 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
2291 PCI_ANY_ID, PCI_ANY_ID },
2292 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
2293 PCI_ANY_ID, PCI_ANY_ID },
2294 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
2295 PCI_ANY_ID, PCI_ANY_ID },
2296 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
2297 PCI_ANY_ID, PCI_ANY_ID },
2298 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
2299 PCI_ANY_ID, PCI_ANY_ID },
2300 {0} /* Terminating entry */
2301};
2302MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2303
2304
2305static struct pci_driver mptsas_driver = {
2306 .name = "mptsas",
2307 .id_table = mptsas_pci_table,
2308 .probe = mptsas_probe,
2309 .remove = __devexit_p(mptsas_remove),
2310 .shutdown = mptscsih_shutdown,
2311#ifdef CONFIG_PM
2312 .suspend = mptscsih_suspend,
2313 .resume = mptscsih_resume,
2314#endif
2315};
2316
2317static int __init
2318mptsas_init(void)
2319{
2320 show_mptmod_ver(my_NAME, my_VERSION);
2321
2322 mptsas_transport_template =
2323 sas_attach_transport(&mptsas_transport_functions);
2324 if (!mptsas_transport_template)
2325 return -ENODEV;
2326
2327 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
2328 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
2329 mptsasInternalCtx =
2330 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002331 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002332
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002333 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07002334 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002335 ": Registered for IOC event notifications\n"));
2336 }
2337
2338 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
2339 dprintk((KERN_INFO MYNAM
2340 ": Registered for IOC reset notifications\n"));
2341 }
2342
2343 return pci_register_driver(&mptsas_driver);
2344}
2345
2346static void __exit
2347mptsas_exit(void)
2348{
2349 pci_unregister_driver(&mptsas_driver);
2350 sas_release_transport(mptsas_transport_template);
2351
2352 mpt_reset_deregister(mptsasDoneCtx);
2353 mpt_event_deregister(mptsasDoneCtx);
2354
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002355 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002356 mpt_deregister(mptsasInternalCtx);
2357 mpt_deregister(mptsasTaskCtx);
2358 mpt_deregister(mptsasDoneCtx);
2359}
2360
2361module_init(mptsas_init);
2362module_exit(mptsas_exit);