blob: 85689ab46cbc26fcc30db0e471cc5081abd5dc66 [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, Ericc73787e2006-01-26 16:20:06 -070092 MPTSAS_ADD_RAID,
93 MPTSAS_DEL_RAID,
Moore, Ericbd23e942006-04-17 12:43:04 -060094 MPTSAS_IGNORE_EVENT,
Christoph Hellwig9a28f492006-01-13 18:04:41 +010095};
96
97struct mptsas_hotplug_event {
98 struct work_struct work;
99 MPT_ADAPTER *ioc;
100 enum mptsas_hotplug_action event_type;
101 u64 sas_address;
102 u32 channel;
103 u32 id;
104 u32 device_info;
105 u16 handle;
106 u16 parent_handle;
107 u8 phy_id;
Moore, Ericf44e5462006-03-14 09:14:21 -0700108 u8 phys_disk_num;
109 u8 phys_disk_num_valid;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100110};
111
Moore, Erice6b2d762006-03-14 09:14:24 -0700112struct mptsas_discovery_event {
113 struct work_struct work;
114 MPT_ADAPTER *ioc;
115};
116
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200117/*
118 * SAS topology structures
119 *
120 * The MPT Fusion firmware interface spreads information about the
121 * SAS topology over many manufacture pages, thus we need some data
122 * structure to collect it and process it for the SAS transport class.
123 */
124
125struct mptsas_devinfo {
126 u16 handle; /* unique id to address this device */
Moore, Ericc73787e2006-01-26 16:20:06 -0700127 u16 handle_parent; /* unique id to address parent device */
Christoph Hellwige3094442006-02-16 13:25:36 +0100128 u16 handle_enclosure; /* enclosure identifier of the enclosure */
129 u16 slot; /* physical slot in enclosure */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200130 u8 phy_id; /* phy number of parent device */
131 u8 port_id; /* sas physical port this device
132 is assoc'd with */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100133 u8 id; /* logical target id of this device */
134 u8 channel; /* logical bus number of this device */
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200135 u64 sas_address; /* WWN of this device,
136 SATA is assigned by HBA,expander */
137 u32 device_info; /* bitfield detailed info about this device */
138};
139
140struct mptsas_phyinfo {
141 u8 phy_id; /* phy index */
142 u8 port_id; /* port number this phy is part of */
143 u8 negotiated_link_rate; /* nego'd link rate for this phy */
144 u8 hw_link_rate; /* hardware max/min phys link rate */
145 u8 programmed_link_rate; /* programmed max/min phy link rate */
146 struct mptsas_devinfo identify; /* point to phy device info */
147 struct mptsas_devinfo attached; /* point to attached device info */
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100148 struct sas_phy *phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200149 struct sas_rphy *rphy;
Moore, Ericf44e5462006-03-14 09:14:21 -0700150 struct scsi_target *starget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200151};
152
153struct mptsas_portinfo {
154 struct list_head list;
155 u16 handle; /* unique id to address this */
156 u8 num_phys; /* number of phys */
157 struct mptsas_phyinfo *phy_info;
158};
159
Christoph Hellwige3094442006-02-16 13:25:36 +0100160struct mptsas_enclosure {
161 u64 enclosure_logical_id; /* The WWN for the enclosure */
162 u16 enclosure_handle; /* unique id to address this */
163 u16 flags; /* details enclosure management */
164 u16 num_slot; /* num slots */
165 u16 start_slot; /* first slot */
166 u8 start_id; /* starting logical target id */
167 u8 start_channel; /* starting logical channel id */
168 u8 sep_id; /* SEP device logical target id */
169 u8 sep_channel; /* SEP channel logical channel id */
170};
171
Christoph Hellwigb5141122005-10-28 22:07:41 +0200172#ifdef SASDEBUG
173static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
174{
175 printk("---- IO UNIT PAGE 0 ------------\n");
176 printk("Handle=0x%X\n",
177 le16_to_cpu(phy_data->AttachedDeviceHandle));
178 printk("Controller Handle=0x%X\n",
179 le16_to_cpu(phy_data->ControllerDevHandle));
180 printk("Port=0x%X\n", phy_data->Port);
181 printk("Port Flags=0x%X\n", phy_data->PortFlags);
182 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
183 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
184 printk("Controller PHY Device Info=0x%X\n",
185 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
186 printk("DiscoveryStatus=0x%X\n",
187 le32_to_cpu(phy_data->DiscoveryStatus));
188 printk("\n");
189}
190
191static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
192{
193 __le64 sas_address;
194
195 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
196
197 printk("---- SAS PHY PAGE 0 ------------\n");
198 printk("Attached Device Handle=0x%X\n",
199 le16_to_cpu(pg0->AttachedDevHandle));
200 printk("SAS Address=0x%llX\n",
201 (unsigned long long)le64_to_cpu(sas_address));
202 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
203 printk("Attached Device Info=0x%X\n",
204 le32_to_cpu(pg0->AttachedDeviceInfo));
205 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
206 printk("Change Count=0x%X\n", pg0->ChangeCount);
207 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
208 printk("\n");
209}
210
211static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
212{
213 printk("---- SAS PHY PAGE 1 ------------\n");
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200214 printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
215 printk("Running Disparity Error Count=0x%x\n",
Christoph Hellwigb5141122005-10-28 22:07:41 +0200216 pg1->RunningDisparityErrorCount);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200217 printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
218 printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
219 printk("\n");
Christoph Hellwigb5141122005-10-28 22:07:41 +0200220}
221
222static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
223{
224 __le64 sas_address;
225
226 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
227
228 printk("---- SAS DEVICE PAGE 0 ---------\n");
229 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
Christoph Hellwige3094442006-02-16 13:25:36 +0100230 printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200231 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
232 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
233 printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
234 printk("Target ID=0x%X\n", pg0->TargetID);
235 printk("Bus=0x%X\n", pg0->Bus);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200236 /* The PhyNum field specifies the PHY number of the parent
237 * device this device is linked to
238 */
239 printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
240 printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200241 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
242 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
243 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
244 printk("\n");
245}
246
247static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
248{
249 printk("---- SAS EXPANDER PAGE 1 ------------\n");
250
251 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
Christoph Hellwigf9a2d2e2005-10-19 20:01:47 +0200252 printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
Christoph Hellwigb5141122005-10-28 22:07:41 +0200253 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
254 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
255 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
256 printk("Owner Device Handle=0x%X\n",
257 le16_to_cpu(pg1->OwnerDevHandle));
258 printk("Attached Device Handle=0x%X\n",
259 le16_to_cpu(pg1->AttachedDevHandle));
260}
261#else
262#define mptsas_print_phy_data(phy_data) do { } while (0)
263#define mptsas_print_phy_pg0(pg0) do { } while (0)
264#define mptsas_print_phy_pg1(pg1) do { } while (0)
265#define mptsas_print_device_pg0(pg0) do { } while (0)
266#define mptsas_print_expander_pg1(pg1) do { } while (0)
267#endif
268
Christoph Hellwige3094442006-02-16 13:25:36 +0100269static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
270{
271 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
272 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
273}
274
275static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
276{
277 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
278 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
279}
280
Moore, Erice6b2d762006-03-14 09:14:24 -0700281/*
282 * mptsas_find_portinfo_by_handle
283 *
284 * This function should be called with the sas_topology_mutex already held
285 */
286static struct mptsas_portinfo *
287mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
288{
289 struct mptsas_portinfo *port_info, *rc=NULL;
290 int i;
291
292 list_for_each_entry(port_info, &ioc->sas_topology, list)
293 for (i = 0; i < port_info->num_phys; i++)
294 if (port_info->phy_info[i].identify.handle == handle) {
295 rc = port_info;
296 goto out;
297 }
298 out:
299 return rc;
300}
301
Moore, Ericbd23e942006-04-17 12:43:04 -0600302/*
303 * Returns true if there is a scsi end device
304 */
305static inline int
306mptsas_is_end_device(struct mptsas_devinfo * attached)
307{
308 if ((attached->handle) &&
309 (attached->device_info &
310 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
311 ((attached->device_info &
312 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
313 (attached->device_info &
314 MPI_SAS_DEVICE_INFO_STP_TARGET) |
315 (attached->device_info &
316 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
317 return 1;
318 else
319 return 0;
320}
321
Christoph Hellwige3094442006-02-16 13:25:36 +0100322static int
Moore, Eric52435432006-03-14 09:14:15 -0700323mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100324 u32 form, u32 form_specific)
325{
326 ConfigExtendedPageHeader_t hdr;
327 CONFIGPARMS cfg;
328 SasEnclosurePage0_t *buffer;
329 dma_addr_t dma_handle;
330 int error;
331 __le64 le_identifier;
332
333 memset(&hdr, 0, sizeof(hdr));
334 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
335 hdr.PageNumber = 0;
336 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
337 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
338
339 cfg.cfghdr.ehdr = &hdr;
340 cfg.physAddr = -1;
341 cfg.pageAddr = form + form_specific;
342 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
343 cfg.dir = 0; /* read */
344 cfg.timeout = 10;
345
346 error = mpt_config(ioc, &cfg);
347 if (error)
348 goto out;
349 if (!hdr.ExtPageLength) {
350 error = -ENXIO;
351 goto out;
352 }
353
354 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
355 &dma_handle);
356 if (!buffer) {
357 error = -ENOMEM;
358 goto out;
359 }
360
361 cfg.physAddr = dma_handle;
362 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
363
364 error = mpt_config(ioc, &cfg);
365 if (error)
366 goto out_free_consistent;
367
368 /* save config data */
369 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
370 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
371 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
372 enclosure->flags = le16_to_cpu(buffer->Flags);
373 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
374 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
375 enclosure->start_id = buffer->StartTargetID;
376 enclosure->start_channel = buffer->StartBus;
377 enclosure->sep_id = buffer->SEPTargetID;
378 enclosure->sep_channel = buffer->SEPBus;
379
380 out_free_consistent:
381 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
382 buffer, dma_handle);
383 out:
384 return error;
385}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200386
James Bottomleyf013db32006-03-18 14:54:36 -0600387static int
388mptsas_slave_configure(struct scsi_device *sdev)
389{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600390 struct Scsi_Host *host = sdev->host;
391 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
392
393 /*
394 * RAID volumes placed beyond the last expected port.
395 * Ignore sending sas mode pages in that case..
396 */
397 if (sdev->channel < hd->ioc->num_ports)
398 sas_read_port_mode_page(sdev);
James Bottomleyf013db32006-03-18 14:54:36 -0600399
400 return mptscsih_slave_configure(sdev);
401}
402
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200403/*
404 * This is pretty ugly. We will be able to seriously clean it up
405 * once the DV code in mptscsih goes away and we can properly
406 * implement ->target_alloc.
407 */
408static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700409mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200410{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700411 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200412 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
413 struct sas_rphy *rphy;
414 struct mptsas_portinfo *p;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700415 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200416 VirtDevice *vdev;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700417 struct scsi_target *starget;
Moore, Eric914c2d82006-03-14 09:19:36 -0700418 u32 target_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200419 int i;
420
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100421 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200422 if (!vdev) {
423 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
424 hd->ioc->name, sizeof(VirtDevice));
425 return -ENOMEM;
426 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700427 sdev->hostdata = vdev;
428 starget = scsi_target(sdev);
429 vtarget = starget->hostdata;
Moore, Eric914c2d82006-03-14 09:19:36 -0700430 vtarget->ioc_id = hd->ioc->id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700431 vdev->vtarget = vtarget;
432 if (vtarget->num_luns == 0) {
433 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
434 hd->Targets[sdev->id] = vtarget;
435 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200436
Moore, Eric816aa902006-01-13 16:25:20 -0700437 /*
438 RAID volumes placed beyond the last expected port.
439 */
440 if (sdev->channel == hd->ioc->num_ports) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700441 target_id = sdev->id;
442 vtarget->bus_id = 0;
Moore, Eric816aa902006-01-13 16:25:20 -0700443 vdev->lun = 0;
444 goto out;
445 }
446
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700447 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100448 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200449 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
450 for (i = 0; i < p->num_phys; i++) {
451 if (p->phy_info[i].attached.sas_address ==
452 rphy->identify.sas_address) {
Moore, Eric914c2d82006-03-14 09:19:36 -0700453 target_id = p->phy_info[i].attached.id;
454 vtarget->bus_id = p->phy_info[i].attached.channel;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700455 vdev->lun = sdev->lun;
Moore, Ericf44e5462006-03-14 09:14:21 -0700456 p->phy_info[i].starget = sdev->sdev_target;
457 /*
458 * Exposing hidden disk (RAID)
459 */
460 if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
461 target_id = mptscsih_raid_id_to_num(hd,
462 target_id);
463 vdev->vtarget->tflags |=
464 MPT_TARGET_FLAGS_RAID_COMPONENT;
465 sdev->no_uld_attach = 1;
466 }
Moore, Eric914c2d82006-03-14 09:19:36 -0700467 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200468 goto out;
469 }
470 }
471 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100472 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200473
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200474 kfree(vdev);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100475 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200476
477 out:
Moore, Eric914c2d82006-03-14 09:19:36 -0700478 vtarget->target_id = target_id;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700479 vtarget->num_luns++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200480 return 0;
481}
482
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100483static void
484mptsas_slave_destroy(struct scsi_device *sdev)
485{
486 struct Scsi_Host *host = sdev->host;
487 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700488 VirtDevice *vdev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100489
490 /*
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700491 * Issue target reset to flush firmware outstanding commands.
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100492 */
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700493 vdev = sdev->hostdata;
494 if (vdev->configured_lun){
495 if (mptscsih_TMHandler(hd,
496 MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
Moore, Eric914c2d82006-03-14 09:19:36 -0700497 vdev->vtarget->bus_id,
498 vdev->vtarget->target_id,
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700499 0, 0, 5 /* 5 second timeout */)
500 < 0){
501
502 /* The TM request failed!
503 * Fatal error case.
504 */
505 printk(MYIOC_s_WARN_FMT
506 "Error processing TaskMgmt id=%d TARGET_RESET\n",
507 hd->ioc->name,
Moore, Eric914c2d82006-03-14 09:19:36 -0700508 vdev->vtarget->target_id);
Moore, Eric7d3eecf2006-01-25 18:05:12 -0700509
510 hd->tmPending = 0;
511 hd->tmState = TM_STATE_NONE;
512 }
513 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100514 mptscsih_slave_destroy(sdev);
515}
516
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200517static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700518 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200519 .proc_name = "mptsas",
520 .proc_info = mptscsih_proc_info,
521 .name = "MPT SPI Host",
522 .info = mptscsih_info,
523 .queuecommand = mptscsih_qcmd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700524 .target_alloc = mptscsih_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200525 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -0600526 .slave_configure = mptsas_slave_configure,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700527 .target_destroy = mptscsih_target_destroy,
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100528 .slave_destroy = mptsas_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200529 .change_queue_depth = mptscsih_change_queue_depth,
530 .eh_abort_handler = mptscsih_abort,
531 .eh_device_reset_handler = mptscsih_dev_reset,
532 .eh_bus_reset_handler = mptscsih_bus_reset,
533 .eh_host_reset_handler = mptscsih_host_reset,
534 .bios_param = mptscsih_bios_param,
535 .can_queue = MPT_FC_CAN_QUEUE,
536 .this_id = -1,
537 .sg_tablesize = MPT_SCSI_SG_DEPTH,
538 .max_sectors = 8192,
539 .cmd_per_lun = 7,
540 .use_clustering = ENABLE_CLUSTERING,
541};
542
Christoph Hellwigb5141122005-10-28 22:07:41 +0200543static int mptsas_get_linkerrors(struct sas_phy *phy)
544{
545 MPT_ADAPTER *ioc = phy_to_ioc(phy);
546 ConfigExtendedPageHeader_t hdr;
547 CONFIGPARMS cfg;
548 SasPhyPage1_t *buffer;
549 dma_addr_t dma_handle;
550 int error;
551
552 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
553 hdr.ExtPageLength = 0;
554 hdr.PageNumber = 1 /* page number 1*/;
555 hdr.Reserved1 = 0;
556 hdr.Reserved2 = 0;
557 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
558 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
559
560 cfg.cfghdr.ehdr = &hdr;
561 cfg.physAddr = -1;
562 cfg.pageAddr = phy->identify.phy_identifier;
563 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
564 cfg.dir = 0; /* read */
565 cfg.timeout = 10;
566
567 error = mpt_config(ioc, &cfg);
568 if (error)
569 return error;
570 if (!hdr.ExtPageLength)
571 return -ENXIO;
572
573 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
574 &dma_handle);
575 if (!buffer)
576 return -ENOMEM;
577
578 cfg.physAddr = dma_handle;
579 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
580
581 error = mpt_config(ioc, &cfg);
582 if (error)
583 goto out_free_consistent;
584
585 mptsas_print_phy_pg1(buffer);
586
587 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
588 phy->running_disparity_error_count =
589 le32_to_cpu(buffer->RunningDisparityErrorCount);
590 phy->loss_of_dword_sync_count =
591 le32_to_cpu(buffer->LossDwordSynchCount);
592 phy->phy_reset_problem_count =
593 le32_to_cpu(buffer->PhyResetProblemCount);
594
595 out_free_consistent:
596 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
597 buffer, dma_handle);
598 return error;
599}
600
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200601static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
602 MPT_FRAME_HDR *reply)
603{
604 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
605 if (reply != NULL) {
606 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
607 memcpy(ioc->sas_mgmt.reply, reply,
608 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
609 }
610 complete(&ioc->sas_mgmt.done);
611 return 1;
612}
613
614static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
615{
616 MPT_ADAPTER *ioc = phy_to_ioc(phy);
617 SasIoUnitControlRequest_t *req;
618 SasIoUnitControlReply_t *reply;
619 MPT_FRAME_HDR *mf;
620 MPIHeader_t *hdr;
621 unsigned long timeleft;
622 int error = -ERESTARTSYS;
623
624 /* not implemented for expanders */
625 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
626 return -ENXIO;
627
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100628 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200629 goto out;
630
631 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
632 if (!mf) {
633 error = -ENOMEM;
634 goto out_unlock;
635 }
636
637 hdr = (MPIHeader_t *) mf;
638 req = (SasIoUnitControlRequest_t *)mf;
639 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
640 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
641 req->MsgContext = hdr->MsgContext;
642 req->Operation = hard_reset ?
643 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
644 req->PhyNum = phy->identify.phy_identifier;
645
646 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
647
648 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
649 10 * HZ);
650 if (!timeleft) {
651 /* On timeout reset the board */
652 mpt_free_msg_frame(ioc, mf);
653 mpt_HardResetHandler(ioc, CAN_SLEEP);
654 error = -ETIMEDOUT;
655 goto out_unlock;
656 }
657
658 /* a reply frame is expected */
659 if ((ioc->sas_mgmt.status &
660 MPT_IOCTL_STATUS_RF_VALID) == 0) {
661 error = -ENXIO;
662 goto out_unlock;
663 }
664
665 /* process the completed Reply Message Frame */
666 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
667 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
668 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
669 __FUNCTION__,
670 reply->IOCStatus,
671 reply->IOCLogInfo);
672 error = -ENXIO;
673 goto out_unlock;
674 }
675
676 error = 0;
677
678 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +0100679 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200680 out:
681 return error;
682}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200683
Christoph Hellwige3094442006-02-16 13:25:36 +0100684static int
685mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
686{
687 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
688 int i, error;
689 struct mptsas_portinfo *p;
690 struct mptsas_enclosure enclosure_info;
691 u64 enclosure_handle;
692
693 mutex_lock(&ioc->sas_topology_mutex);
694 list_for_each_entry(p, &ioc->sas_topology, list) {
695 for (i = 0; i < p->num_phys; i++) {
696 if (p->phy_info[i].attached.sas_address ==
697 rphy->identify.sas_address) {
698 enclosure_handle = p->phy_info[i].
699 attached.handle_enclosure;
700 goto found_info;
701 }
702 }
703 }
704 mutex_unlock(&ioc->sas_topology_mutex);
705 return -ENXIO;
706
707 found_info:
708 mutex_unlock(&ioc->sas_topology_mutex);
709 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -0700710 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +0100711 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
712 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
713 if (!error)
714 *identifier = enclosure_info.enclosure_logical_id;
715 return error;
716}
717
718static int
719mptsas_get_bay_identifier(struct sas_rphy *rphy)
720{
721 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
722 struct mptsas_portinfo *p;
723 int i, rc;
724
725 mutex_lock(&ioc->sas_topology_mutex);
726 list_for_each_entry(p, &ioc->sas_topology, list) {
727 for (i = 0; i < p->num_phys; i++) {
728 if (p->phy_info[i].attached.sas_address ==
729 rphy->identify.sas_address) {
730 rc = p->phy_info[i].attached.slot;
731 goto out;
732 }
733 }
734 }
735 rc = -ENXIO;
736 out:
737 mutex_unlock(&ioc->sas_topology_mutex);
738 return rc;
739}
740
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200741static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +0200742 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +0100743 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
744 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +0200745 .phy_reset = mptsas_phy_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200746};
747
748static struct scsi_transport_template *mptsas_transport_template;
749
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200750static int
751mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
752{
753 ConfigExtendedPageHeader_t hdr;
754 CONFIGPARMS cfg;
755 SasIOUnitPage0_t *buffer;
756 dma_addr_t dma_handle;
757 int error, i;
758
759 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
760 hdr.ExtPageLength = 0;
761 hdr.PageNumber = 0;
762 hdr.Reserved1 = 0;
763 hdr.Reserved2 = 0;
764 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
765 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
766
767 cfg.cfghdr.ehdr = &hdr;
768 cfg.physAddr = -1;
769 cfg.pageAddr = 0;
770 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
771 cfg.dir = 0; /* read */
772 cfg.timeout = 10;
773
774 error = mpt_config(ioc, &cfg);
775 if (error)
776 goto out;
777 if (!hdr.ExtPageLength) {
778 error = -ENXIO;
779 goto out;
780 }
781
782 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
783 &dma_handle);
784 if (!buffer) {
785 error = -ENOMEM;
786 goto out;
787 }
788
789 cfg.physAddr = dma_handle;
790 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
791
792 error = mpt_config(ioc, &cfg);
793 if (error)
794 goto out_free_consistent;
795
796 port_info->num_phys = buffer->NumPhys;
797 port_info->phy_info = kcalloc(port_info->num_phys,
798 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
799 if (!port_info->phy_info) {
800 error = -ENOMEM;
801 goto out_free_consistent;
802 }
803
Moore, Ericdb9c9172006-03-14 09:14:18 -0700804 if (port_info->num_phys)
805 port_info->handle =
806 le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200807 for (i = 0; i < port_info->num_phys; i++) {
808 mptsas_print_phy_data(&buffer->PhyData[i]);
809 port_info->phy_info[i].phy_id = i;
810 port_info->phy_info[i].port_id =
811 buffer->PhyData[i].Port;
812 port_info->phy_info[i].negotiated_link_rate =
813 buffer->PhyData[i].NegotiatedLinkRate;
814 }
815
816 out_free_consistent:
817 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
818 buffer, dma_handle);
819 out:
820 return error;
821}
822
823static int
824mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
825 u32 form, u32 form_specific)
826{
827 ConfigExtendedPageHeader_t hdr;
828 CONFIGPARMS cfg;
829 SasPhyPage0_t *buffer;
830 dma_addr_t dma_handle;
831 int error;
832
833 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
834 hdr.ExtPageLength = 0;
835 hdr.PageNumber = 0;
836 hdr.Reserved1 = 0;
837 hdr.Reserved2 = 0;
838 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
839 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
840
841 cfg.cfghdr.ehdr = &hdr;
842 cfg.dir = 0; /* read */
843 cfg.timeout = 10;
844
845 /* Get Phy Pg 0 for each Phy. */
846 cfg.physAddr = -1;
847 cfg.pageAddr = form + form_specific;
848 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
849
850 error = mpt_config(ioc, &cfg);
851 if (error)
852 goto out;
853
854 if (!hdr.ExtPageLength) {
855 error = -ENXIO;
856 goto out;
857 }
858
859 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
860 &dma_handle);
861 if (!buffer) {
862 error = -ENOMEM;
863 goto out;
864 }
865
866 cfg.physAddr = dma_handle;
867 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
868
869 error = mpt_config(ioc, &cfg);
870 if (error)
871 goto out_free_consistent;
872
873 mptsas_print_phy_pg0(buffer);
874
875 phy_info->hw_link_rate = buffer->HwLinkRate;
876 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
877 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
878 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
879
880 out_free_consistent:
881 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
882 buffer, dma_handle);
883 out:
884 return error;
885}
886
887static int
888mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
889 u32 form, u32 form_specific)
890{
891 ConfigExtendedPageHeader_t hdr;
892 CONFIGPARMS cfg;
893 SasDevicePage0_t *buffer;
894 dma_addr_t dma_handle;
895 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -0600896 int error=0;
897
898 if (ioc->sas_discovery_runtime &&
899 mptsas_is_end_device(device_info))
900 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200901
902 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
903 hdr.ExtPageLength = 0;
904 hdr.PageNumber = 0;
905 hdr.Reserved1 = 0;
906 hdr.Reserved2 = 0;
907 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
908 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
909
910 cfg.cfghdr.ehdr = &hdr;
911 cfg.pageAddr = form + form_specific;
912 cfg.physAddr = -1;
913 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
914 cfg.dir = 0; /* read */
915 cfg.timeout = 10;
916
Moore, Ericdb9c9172006-03-14 09:14:18 -0700917 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200918 error = mpt_config(ioc, &cfg);
919 if (error)
920 goto out;
921 if (!hdr.ExtPageLength) {
922 error = -ENXIO;
923 goto out;
924 }
925
926 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
927 &dma_handle);
928 if (!buffer) {
929 error = -ENOMEM;
930 goto out;
931 }
932
933 cfg.physAddr = dma_handle;
934 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
935
936 error = mpt_config(ioc, &cfg);
937 if (error)
938 goto out_free_consistent;
939
940 mptsas_print_device_pg0(buffer);
941
942 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -0700943 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +0100944 device_info->handle_enclosure =
945 le16_to_cpu(buffer->EnclosureHandle);
946 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200947 device_info->phy_id = buffer->PhyNum;
948 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100949 device_info->id = buffer->TargetID;
950 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200951 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
952 device_info->sas_address = le64_to_cpu(sas_address);
953 device_info->device_info =
954 le32_to_cpu(buffer->DeviceInfo);
955
956 out_free_consistent:
957 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
958 buffer, dma_handle);
959 out:
960 return error;
961}
962
963static int
964mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
965 u32 form, u32 form_specific)
966{
967 ConfigExtendedPageHeader_t hdr;
968 CONFIGPARMS cfg;
969 SasExpanderPage0_t *buffer;
970 dma_addr_t dma_handle;
971 int error;
972
973 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
974 hdr.ExtPageLength = 0;
975 hdr.PageNumber = 0;
976 hdr.Reserved1 = 0;
977 hdr.Reserved2 = 0;
978 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
979 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
980
981 cfg.cfghdr.ehdr = &hdr;
982 cfg.physAddr = -1;
983 cfg.pageAddr = form + form_specific;
984 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
985 cfg.dir = 0; /* read */
986 cfg.timeout = 10;
987
Moore, Ericdb9c9172006-03-14 09:14:18 -0700988 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200989 error = mpt_config(ioc, &cfg);
990 if (error)
991 goto out;
992
993 if (!hdr.ExtPageLength) {
994 error = -ENXIO;
995 goto out;
996 }
997
998 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
999 &dma_handle);
1000 if (!buffer) {
1001 error = -ENOMEM;
1002 goto out;
1003 }
1004
1005 cfg.physAddr = dma_handle;
1006 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1007
1008 error = mpt_config(ioc, &cfg);
1009 if (error)
1010 goto out_free_consistent;
1011
1012 /* save config data */
1013 port_info->num_phys = buffer->NumPhys;
1014 port_info->handle = le16_to_cpu(buffer->DevHandle);
1015 port_info->phy_info = kcalloc(port_info->num_phys,
1016 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
1017 if (!port_info->phy_info) {
1018 error = -ENOMEM;
1019 goto out_free_consistent;
1020 }
1021
1022 out_free_consistent:
1023 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1024 buffer, dma_handle);
1025 out:
1026 return error;
1027}
1028
1029static int
1030mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1031 u32 form, u32 form_specific)
1032{
1033 ConfigExtendedPageHeader_t hdr;
1034 CONFIGPARMS cfg;
1035 SasExpanderPage1_t *buffer;
1036 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001037 int error=0;
1038
1039 if (ioc->sas_discovery_runtime &&
1040 mptsas_is_end_device(&phy_info->attached))
1041 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001042
1043 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1044 hdr.ExtPageLength = 0;
1045 hdr.PageNumber = 1;
1046 hdr.Reserved1 = 0;
1047 hdr.Reserved2 = 0;
1048 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1049 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1050
1051 cfg.cfghdr.ehdr = &hdr;
1052 cfg.physAddr = -1;
1053 cfg.pageAddr = form + form_specific;
1054 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1055 cfg.dir = 0; /* read */
1056 cfg.timeout = 10;
1057
1058 error = mpt_config(ioc, &cfg);
1059 if (error)
1060 goto out;
1061
1062 if (!hdr.ExtPageLength) {
1063 error = -ENXIO;
1064 goto out;
1065 }
1066
1067 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1068 &dma_handle);
1069 if (!buffer) {
1070 error = -ENOMEM;
1071 goto out;
1072 }
1073
1074 cfg.physAddr = dma_handle;
1075 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1076
1077 error = mpt_config(ioc, &cfg);
1078 if (error)
1079 goto out_free_consistent;
1080
1081
1082 mptsas_print_expander_pg1(buffer);
1083
1084 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001085 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001086 phy_info->port_id = buffer->PhysicalPort;
1087 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1088 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1089 phy_info->hw_link_rate = buffer->HwLinkRate;
1090 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1091 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1092
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001093 out_free_consistent:
1094 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1095 buffer, dma_handle);
1096 out:
1097 return error;
1098}
1099
1100static void
1101mptsas_parse_device_info(struct sas_identify *identify,
1102 struct mptsas_devinfo *device_info)
1103{
1104 u16 protocols;
1105
1106 identify->sas_address = device_info->sas_address;
1107 identify->phy_identifier = device_info->phy_id;
1108
1109 /*
1110 * Fill in Phy Initiator Port Protocol.
1111 * Bits 6:3, more than one bit can be set, fall through cases.
1112 */
1113 protocols = device_info->device_info & 0x78;
1114 identify->initiator_port_protocols = 0;
1115 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1116 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1117 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1118 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1119 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1120 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1121 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1122 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1123
1124 /*
1125 * Fill in Phy Target Port Protocol.
1126 * Bits 10:7, more than one bit can be set, fall through cases.
1127 */
1128 protocols = device_info->device_info & 0x780;
1129 identify->target_port_protocols = 0;
1130 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1131 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1132 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1133 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1134 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1135 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1136 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1137 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1138
1139 /*
1140 * Fill in Attached device type.
1141 */
1142 switch (device_info->device_info &
1143 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1144 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1145 identify->device_type = SAS_PHY_UNUSED;
1146 break;
1147 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1148 identify->device_type = SAS_END_DEVICE;
1149 break;
1150 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1151 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1152 break;
1153 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1154 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1155 break;
1156 }
1157}
1158
1159static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001160 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001161{
Moore, Erice6b2d762006-03-14 09:14:24 -07001162 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001163 struct sas_phy *phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001164 int error;
1165
Moore, Erice6b2d762006-03-14 09:14:24 -07001166 if (!dev)
1167 return -ENODEV;
1168
1169 if (!phy_info->phy) {
1170 phy = sas_phy_alloc(dev, index);
1171 if (!phy)
1172 return -ENOMEM;
1173 } else
1174 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001175
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001176 phy->port_identifier = phy_info->port_id;
1177 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001178
1179 /*
1180 * Set Negotiated link rate.
1181 */
1182 switch (phy_info->negotiated_link_rate) {
1183 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001184 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001185 break;
1186 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001187 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001188 break;
1189 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001190 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001191 break;
1192 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001193 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001194 break;
1195 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1196 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1197 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001198 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001199 break;
1200 }
1201
1202 /*
1203 * Set Max hardware link rate.
1204 */
1205 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1206 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001207 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001208 break;
1209 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001210 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001211 break;
1212 default:
1213 break;
1214 }
1215
1216 /*
1217 * Set Max programmed link rate.
1218 */
1219 switch (phy_info->programmed_link_rate &
1220 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1221 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001222 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001223 break;
1224 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001225 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001226 break;
1227 default:
1228 break;
1229 }
1230
1231 /*
1232 * Set Min hardware link rate.
1233 */
1234 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1235 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001236 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001237 break;
1238 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001239 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001240 break;
1241 default:
1242 break;
1243 }
1244
1245 /*
1246 * Set Min programmed link rate.
1247 */
1248 switch (phy_info->programmed_link_rate &
1249 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1250 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001251 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001252 break;
1253 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001254 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001255 break;
1256 default:
1257 break;
1258 }
1259
Moore, Erice6b2d762006-03-14 09:14:24 -07001260 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001261
Moore, Erice6b2d762006-03-14 09:14:24 -07001262 if (local)
1263 phy->local_attached = 1;
1264
1265 error = sas_phy_add(phy);
1266 if (error) {
1267 sas_phy_free(phy);
1268 return error;
1269 }
1270 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001271 }
1272
Moore, Erice6b2d762006-03-14 09:14:24 -07001273 if ((phy_info->attached.handle) &&
1274 (!phy_info->rphy)) {
1275
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001276 struct sas_rphy *rphy;
James Bottomleyf013db32006-03-18 14:54:36 -06001277 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001278
Moore, Erice6b2d762006-03-14 09:14:24 -07001279 ioc = phy_to_ioc(phy_info->phy);
1280
1281 /*
1282 * Let the hotplug_work thread handle processing
1283 * the adding/removing of devices that occur
1284 * after start of day.
1285 */
1286 if (ioc->sas_discovery_runtime &&
1287 mptsas_is_end_device(&phy_info->attached))
1288 return 0;
1289
James Bottomleyf013db32006-03-18 14:54:36 -06001290 mptsas_parse_device_info(&identify, &phy_info->attached);
1291 switch (identify.device_type) {
1292 case SAS_END_DEVICE:
1293 rphy = sas_end_device_alloc(phy);
1294 break;
1295 case SAS_EDGE_EXPANDER_DEVICE:
1296 case SAS_FANOUT_EXPANDER_DEVICE:
1297 rphy = sas_expander_alloc(phy, identify.device_type);
1298 break;
1299 default:
1300 rphy = NULL;
1301 break;
1302 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001303 if (!rphy)
1304 return 0; /* non-fatal: an rphy can be added later */
1305
James Bottomleyf013db32006-03-18 14:54:36 -06001306 rphy->identify = identify;
1307
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001308 error = sas_rphy_add(rphy);
1309 if (error) {
1310 sas_rphy_free(rphy);
1311 return error;
1312 }
1313
1314 phy_info->rphy = rphy;
1315 }
1316
1317 return 0;
1318}
1319
1320static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001321mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001322{
Moore, Erice6b2d762006-03-14 09:14:24 -07001323 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001324 u32 handle = 0xFFFF;
1325 int error = -ENOMEM, i;
1326
Moore, Erice6b2d762006-03-14 09:14:24 -07001327 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
1328 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001329 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001330
Moore, Erice6b2d762006-03-14 09:14:24 -07001331 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001332 if (error)
1333 goto out_free_port_info;
1334
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001335 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001336 port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
1337 if (!port_info) {
1338 port_info = hba;
1339 list_add_tail(&port_info->list, &ioc->sas_topology);
1340 } else {
1341 port_info->handle = hba->handle;
1342 for (i = 0; i < hba->num_phys; i++)
1343 port_info->phy_info[i].negotiated_link_rate =
1344 hba->phy_info[i].negotiated_link_rate;
1345 if (hba->phy_info)
1346 kfree(hba->phy_info);
1347 kfree(hba);
1348 hba = NULL;
1349 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001350 mutex_unlock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001351 ioc->num_ports = port_info->num_phys;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001352
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001353 for (i = 0; i < port_info->num_phys; i++) {
1354 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
1355 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
1356 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
1357
1358 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
1359 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
1360 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
Eric Moore024358e2005-10-21 20:56:36 +02001361 port_info->phy_info[i].identify.phy_id =
1362 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001363 handle = port_info->phy_info[i].identify.handle;
1364
1365 if (port_info->phy_info[i].attached.handle) {
1366 mptsas_sas_device_pg0(ioc,
1367 &port_info->phy_info[i].attached,
1368 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1369 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1370 port_info->phy_info[i].attached.handle);
1371 }
1372
1373 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07001374 &port_info->phy_info[i], ioc->sas_index, 1);
1375 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001376 }
1377
1378 return 0;
1379
1380 out_free_port_info:
Jesper Juhl8f760782006-06-27 02:55:06 -07001381 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001382 out:
1383 return error;
1384}
1385
1386static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001387mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001388{
Moore, Erice6b2d762006-03-14 09:14:24 -07001389 struct mptsas_portinfo *port_info, *p, *ex;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001390 int error = -ENOMEM, i, j;
1391
Moore, Erice6b2d762006-03-14 09:14:24 -07001392 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1393 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001394 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001395
Moore, Erice6b2d762006-03-14 09:14:24 -07001396 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001397 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1398 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1399 if (error)
1400 goto out_free_port_info;
1401
Moore, Erice6b2d762006-03-14 09:14:24 -07001402 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001403
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001404 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001405 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1406 if (!port_info) {
1407 port_info = ex;
1408 list_add_tail(&port_info->list, &ioc->sas_topology);
1409 } else {
1410 port_info->handle = ex->handle;
1411 if (ex->phy_info)
1412 kfree(ex->phy_info);
1413 kfree(ex);
1414 ex = NULL;
1415 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001416 mutex_unlock(&ioc->sas_topology_mutex);
1417
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001418 for (i = 0; i < port_info->num_phys; i++) {
1419 struct device *parent;
1420
1421 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1422 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1423 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1424
1425 if (port_info->phy_info[i].identify.handle) {
1426 mptsas_sas_device_pg0(ioc,
1427 &port_info->phy_info[i].identify,
1428 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1429 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1430 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001431 port_info->phy_info[i].identify.phy_id =
1432 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001433 }
1434
1435 if (port_info->phy_info[i].attached.handle) {
1436 mptsas_sas_device_pg0(ioc,
1437 &port_info->phy_info[i].attached,
1438 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1439 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1440 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001441 port_info->phy_info[i].attached.phy_id =
1442 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001443 }
1444
1445 /*
1446 * If we find a parent port handle this expander is
1447 * attached to another expander, else it hangs of the
1448 * HBA phys.
1449 */
1450 parent = &ioc->sh->shost_gendev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001451 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001452 list_for_each_entry(p, &ioc->sas_topology, list) {
1453 for (j = 0; j < p->num_phys; j++) {
1454 if (port_info->phy_info[i].identify.handle ==
1455 p->phy_info[j].attached.handle)
1456 parent = &p->phy_info[j].rphy->dev;
1457 }
1458 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001459 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001460
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001461 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001462 ioc->sas_index, 0);
1463 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001464 }
1465
1466 return 0;
1467
1468 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001469 if (ex) {
1470 if (ex->phy_info)
1471 kfree(ex->phy_info);
1472 kfree(ex);
1473 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001474 out:
1475 return error;
1476}
1477
Moore, Erice6b2d762006-03-14 09:14:24 -07001478/*
1479 * mptsas_delete_expander_phys
1480 *
1481 *
1482 * This will traverse topology, and remove expanders
1483 * that are no longer present
1484 */
1485static void
1486mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1487{
1488 struct mptsas_portinfo buffer;
1489 struct mptsas_portinfo *port_info, *n, *parent;
1490 int i;
1491
1492 mutex_lock(&ioc->sas_topology_mutex);
1493 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1494
1495 if (port_info->phy_info &&
1496 (!(port_info->phy_info[0].identify.device_info &
1497 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1498 continue;
1499
1500 if (mptsas_sas_expander_pg0(ioc, &buffer,
1501 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1502 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1503
1504 /*
1505 * Obtain the port_info instance to the parent port
1506 */
1507 parent = mptsas_find_portinfo_by_handle(ioc,
1508 port_info->phy_info[0].identify.handle_parent);
1509
1510 if (!parent)
1511 goto next_port;
1512
1513 /*
1514 * Delete rphys in the parent that point
1515 * to this expander. The transport layer will
1516 * cleanup all the children.
1517 */
1518 for (i = 0; i < parent->num_phys; i++) {
1519 if ((!parent->phy_info[i].rphy) ||
1520 (parent->phy_info[i].attached.sas_address !=
1521 port_info->phy_info[i].identify.sas_address))
1522 continue;
1523 sas_rphy_delete(parent->phy_info[i].rphy);
1524 memset(&parent->phy_info[i].attached, 0,
1525 sizeof(struct mptsas_devinfo));
1526 parent->phy_info[i].rphy = NULL;
1527 parent->phy_info[i].starget = NULL;
1528 }
1529 next_port:
1530 list_del(&port_info->list);
1531 if (port_info->phy_info)
1532 kfree(port_info->phy_info);
1533 kfree(port_info);
1534 }
1535 /*
1536 * Free this memory allocated from inside
1537 * mptsas_sas_expander_pg0
1538 */
1539 if (buffer.phy_info)
1540 kfree(buffer.phy_info);
1541 }
1542 mutex_unlock(&ioc->sas_topology_mutex);
1543}
1544
1545/*
1546 * Start of day discovery
1547 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001548static void
1549mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1550{
1551 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001552 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001553
Moore, Erice6b2d762006-03-14 09:14:24 -07001554 mutex_lock(&ioc->sas_discovery_mutex);
1555 mptsas_probe_hba_phys(ioc);
1556 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001557 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001558 /*
1559 Reporting RAID volumes.
1560 */
1561 if (!ioc->raid_data.pIocPg2)
1562 goto out;
1563 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1564 goto out;
1565 for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1566 scsi_add_device(ioc->sh, ioc->num_ports,
1567 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
1568 }
1569 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07001570 mutex_unlock(&ioc->sas_discovery_mutex);
1571}
1572
1573/*
1574 * Work queue thread to handle Runtime discovery
1575 * Mere purpose is the hot add/delete of expanders
1576 */
1577static void
1578mptscsih_discovery_work(void * arg)
1579{
1580 struct mptsas_discovery_event *ev = arg;
1581 MPT_ADAPTER *ioc = ev->ioc;
1582 u32 handle = 0xFFFF;
1583
1584 mutex_lock(&ioc->sas_discovery_mutex);
1585 ioc->sas_discovery_runtime=1;
1586 mptsas_delete_expander_phys(ioc);
1587 mptsas_probe_hba_phys(ioc);
1588 while (!mptsas_probe_expander_phys(ioc, &handle))
1589 ;
1590 kfree(ev);
1591 ioc->sas_discovery_runtime=0;
1592 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001593}
1594
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001595static struct mptsas_phyinfo *
1596mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
1597{
1598 struct mptsas_portinfo *port_info;
1599 struct mptsas_devinfo device_info;
1600 struct mptsas_phyinfo *phy_info = NULL;
1601 int i, error;
1602
1603 /*
1604 * Retrieve the parent sas_address
1605 */
1606 error = mptsas_sas_device_pg0(ioc, &device_info,
1607 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1608 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1609 parent_handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001610 if (error)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001611 return NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001612
1613 /*
1614 * The phy_info structures are never deallocated during lifetime of
1615 * a host, so the code below is safe without additional refcounting.
1616 */
1617 mutex_lock(&ioc->sas_topology_mutex);
1618 list_for_each_entry(port_info, &ioc->sas_topology, list) {
1619 for (i = 0; i < port_info->num_phys; i++) {
1620 if (port_info->phy_info[i].identify.sas_address ==
1621 device_info.sas_address &&
1622 port_info->phy_info[i].phy_id == phy_id) {
1623 phy_info = &port_info->phy_info[i];
1624 break;
1625 }
1626 }
1627 }
1628 mutex_unlock(&ioc->sas_topology_mutex);
1629
1630 return phy_info;
1631}
1632
1633static struct mptsas_phyinfo *
Moore, Ericc73787e2006-01-26 16:20:06 -07001634mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001635{
1636 struct mptsas_portinfo *port_info;
1637 struct mptsas_phyinfo *phy_info = NULL;
1638 int i;
1639
1640 /*
1641 * The phy_info structures are never deallocated during lifetime of
1642 * a host, so the code below is safe without additional refcounting.
1643 */
1644 mutex_lock(&ioc->sas_topology_mutex);
1645 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Moore, Ericc73787e2006-01-26 16:20:06 -07001646 for (i = 0; i < port_info->num_phys; i++)
1647 if (mptsas_is_end_device(&port_info->phy_info[i].attached))
1648 if (port_info->phy_info[i].attached.id == id) {
1649 phy_info = &port_info->phy_info[i];
1650 break;
1651 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001652 }
1653 mutex_unlock(&ioc->sas_topology_mutex);
1654
1655 return phy_info;
1656}
1657
Moore, Eric4b766472006-03-14 09:14:12 -07001658/*
1659 * Work queue thread to clear the persitency table
1660 */
1661static void
1662mptscsih_sas_persist_clear_table(void * arg)
1663{
1664 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
1665
1666 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
1667}
1668
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001669static void
Moore, Ericf44e5462006-03-14 09:14:21 -07001670mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
1671{
1672 sdev->no_uld_attach = data ? 1 : 0;
1673 scsi_device_reprobe(sdev);
1674}
1675
1676static void
1677mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
1678{
1679 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
1680 mptsas_reprobe_lun);
1681}
1682
Moore, Erice6b2d762006-03-14 09:14:24 -07001683
1684/*
1685 * Work queue thread to handle SAS hotplug events
1686 */
Moore, Ericf44e5462006-03-14 09:14:21 -07001687static void
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001688mptsas_hotplug_work(void *arg)
1689{
1690 struct mptsas_hotplug_event *ev = arg;
1691 MPT_ADAPTER *ioc = ev->ioc;
1692 struct mptsas_phyinfo *phy_info;
1693 struct sas_rphy *rphy;
Moore, Ericc73787e2006-01-26 16:20:06 -07001694 struct scsi_device *sdev;
James Bottomleyf013db32006-03-18 14:54:36 -06001695 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001696 char *ds = NULL;
Moore, Ericc73787e2006-01-26 16:20:06 -07001697 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07001698 VirtTarget *vtarget;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001699
Moore, Erice6b2d762006-03-14 09:14:24 -07001700 mutex_lock(&ioc->sas_discovery_mutex);
1701
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001702 switch (ev->event_type) {
1703 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001704
Moore, Ericc73787e2006-01-26 16:20:06 -07001705 phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001706
Moore, Ericf44e5462006-03-14 09:14:21 -07001707 /*
1708 * Sanity checks, for non-existing phys and remote rphys.
1709 */
1710 if (!phy_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001711 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07001712 if (!phy_info->rphy)
1713 break;
1714 if (phy_info->starget) {
1715 vtarget = phy_info->starget->hostdata;
1716
1717 if (!vtarget)
1718 break;
1719 /*
1720 * Handling RAID components
1721 */
1722 if (ev->phys_disk_num_valid) {
1723 vtarget->target_id = ev->phys_disk_num;
1724 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
1725 mptsas_reprobe_target(vtarget->starget, 1);
1726 break;
1727 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001728 }
1729
Moore, Ericc73787e2006-01-26 16:20:06 -07001730 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1731 ds = "ssp";
1732 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1733 ds = "stp";
1734 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1735 ds = "sata";
1736
1737 printk(MYIOC_s_INFO_FMT
1738 "removing %s device, channel %d, id %d, phy %d\n",
1739 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
1740
Moore, Ericf44e5462006-03-14 09:14:21 -07001741 sas_rphy_delete(phy_info->rphy);
1742 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
1743 phy_info->rphy = NULL;
1744 phy_info->starget = NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001745 break;
1746 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787e2006-01-26 16:20:06 -07001747
Moore, Ericbd23e942006-04-17 12:43:04 -06001748 if (ev->phys_disk_num_valid)
1749 mpt_findImVolumes(ioc);
1750
Moore, Ericc73787e2006-01-26 16:20:06 -07001751 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01001752 * Refresh sas device pg0 data
Moore, Ericc73787e2006-01-26 16:20:06 -07001753 */
Christoph Hellwige3094442006-02-16 13:25:36 +01001754 if (mptsas_sas_device_pg0(ioc, &sas_device,
1755 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
1756 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
1757 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001758
1759 phy_info = mptsas_find_phyinfo_by_parent(ioc,
Christoph Hellwige3094442006-02-16 13:25:36 +01001760 sas_device.handle_parent, sas_device.phy_id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001761
1762 if (!phy_info) {
1763 u32 handle = 0xFFFF;
1764
1765 /*
1766 * Its possible when an expander has been hot added
1767 * containing attached devices, the sas firmware
1768 * may send a RC_ADDED event prior to the
1769 * DISCOVERY STOP event. If that occurs, our
1770 * view of the topology in the driver in respect to this
1771 * expander might of not been setup, and we hit this
1772 * condition.
1773 * Therefore, this code kicks off discovery to
1774 * refresh the data.
1775 * Then again, we check whether the parent phy has
1776 * been created.
1777 */
1778 ioc->sas_discovery_runtime=1;
1779 mptsas_delete_expander_phys(ioc);
1780 mptsas_probe_hba_phys(ioc);
1781 while (!mptsas_probe_expander_phys(ioc, &handle))
1782 ;
1783 ioc->sas_discovery_runtime=0;
1784
1785 phy_info = mptsas_find_phyinfo_by_parent(ioc,
1786 sas_device.handle_parent, sas_device.phy_id);
1787 if (!phy_info)
1788 break;
1789 }
1790
Moore, Ericf44e5462006-03-14 09:14:21 -07001791 if (phy_info->starget) {
1792 vtarget = phy_info->starget->hostdata;
1793
1794 if (!vtarget)
1795 break;
1796 /*
1797 * Handling RAID components
1798 */
1799 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1800 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
1801 vtarget->target_id = ev->id;
1802 mptsas_reprobe_target(phy_info->starget, 0);
1803 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001804 break;
1805 }
1806
Moore, Ericf44e5462006-03-14 09:14:21 -07001807 if (phy_info->rphy)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001808 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001809
Christoph Hellwige3094442006-02-16 13:25:36 +01001810 memcpy(&phy_info->attached, &sas_device,
1811 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001812
Moore, Ericc73787e2006-01-26 16:20:06 -07001813 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1814 ds = "ssp";
1815 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1816 ds = "stp";
1817 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1818 ds = "sata";
1819
1820 printk(MYIOC_s_INFO_FMT
1821 "attaching %s device, channel %d, id %d, phy %d\n",
1822 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
1823
James Bottomleyf013db32006-03-18 14:54:36 -06001824 mptsas_parse_device_info(&identify, &phy_info->attached);
1825 switch (identify.device_type) {
1826 case SAS_END_DEVICE:
1827 rphy = sas_end_device_alloc(phy_info->phy);
1828 break;
1829 case SAS_EDGE_EXPANDER_DEVICE:
1830 case SAS_FANOUT_EXPANDER_DEVICE:
1831 rphy = sas_expander_alloc(phy_info->phy, identify.device_type);
1832 break;
1833 default:
1834 rphy = NULL;
1835 break;
1836 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001837 if (!rphy)
1838 break; /* non-fatal: an rphy can be added later */
1839
James Bottomleyf013db32006-03-18 14:54:36 -06001840 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001841 if (sas_rphy_add(rphy)) {
1842 sas_rphy_free(rphy);
1843 break;
1844 }
1845
1846 phy_info->rphy = rphy;
1847 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07001848 case MPTSAS_ADD_RAID:
1849 sdev = scsi_device_lookup(
1850 ioc->sh,
1851 ioc->num_ports,
1852 ev->id,
1853 0);
1854 if (sdev) {
1855 scsi_device_put(sdev);
1856 break;
1857 }
1858 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001859 "attaching raid volume, channel %d, id %d\n",
Moore, Ericc73787e2006-01-26 16:20:06 -07001860 ioc->name, ioc->num_ports, ev->id);
1861 scsi_add_device(ioc->sh,
1862 ioc->num_ports,
1863 ev->id,
1864 0);
1865 mpt_findImVolumes(ioc);
1866 break;
1867 case MPTSAS_DEL_RAID:
1868 sdev = scsi_device_lookup(
1869 ioc->sh,
1870 ioc->num_ports,
1871 ev->id,
1872 0);
1873 if (!sdev)
1874 break;
1875 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001876 "removing raid volume, channel %d, id %d\n",
Moore, Ericc73787e2006-01-26 16:20:06 -07001877 ioc->name, ioc->num_ports, ev->id);
1878 scsi_remove_device(sdev);
1879 scsi_device_put(sdev);
1880 mpt_findImVolumes(ioc);
1881 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06001882 case MPTSAS_IGNORE_EVENT:
1883 default:
1884 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001885 }
1886
1887 kfree(ev);
Moore, Erice6b2d762006-03-14 09:14:24 -07001888 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001889}
1890
1891static void
1892mptscsih_send_sas_event(MPT_ADAPTER *ioc,
1893 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1894{
1895 struct mptsas_hotplug_event *ev;
1896 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
1897 __le64 sas_address;
1898
1899 if ((device_info &
1900 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
1901 MPI_SAS_DEVICE_INFO_STP_TARGET |
1902 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
1903 return;
1904
Moore, Eric4b766472006-03-14 09:14:12 -07001905 switch (sas_event_data->ReasonCode) {
1906 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
1907 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
1908 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1909 if (!ev) {
1910 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1911 break;
1912 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001913
Moore, Eric4b766472006-03-14 09:14:12 -07001914 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1915 ev->ioc = ioc;
1916 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
1917 ev->parent_handle =
1918 le16_to_cpu(sas_event_data->ParentDevHandle);
1919 ev->channel = sas_event_data->Bus;
1920 ev->id = sas_event_data->TargetID;
1921 ev->phy_id = sas_event_data->PhyNum;
1922 memcpy(&sas_address, &sas_event_data->SASAddress,
1923 sizeof(__le64));
1924 ev->sas_address = le64_to_cpu(sas_address);
1925 ev->device_info = device_info;
1926
1927 if (sas_event_data->ReasonCode &
1928 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
1929 ev->event_type = MPTSAS_ADD_DEVICE;
1930 else
1931 ev->event_type = MPTSAS_DEL_DEVICE;
1932 schedule_work(&ev->work);
1933 break;
1934 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
1935 /*
1936 * Persistent table is full.
1937 */
1938 INIT_WORK(&ioc->mptscsih_persistTask,
1939 mptscsih_sas_persist_clear_table,
1940 (void *)ioc);
1941 schedule_work(&ioc->mptscsih_persistTask);
1942 break;
1943 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
1944 /* TODO */
1945 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
1946 /* TODO */
1947 default:
1948 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001949 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001950}
1951
Moore, Ericc73787e2006-01-26 16:20:06 -07001952static void
1953mptscsih_send_raid_event(MPT_ADAPTER *ioc,
1954 EVENT_DATA_RAID *raid_event_data)
1955{
1956 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06001957 int status = le32_to_cpu(raid_event_data->SettingsStatus);
1958 int state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07001959
1960 if (ioc->bus_type != SAS)
1961 return;
1962
1963 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1964 if (!ev) {
1965 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1966 return;
1967 }
1968
1969 memset(ev,0,sizeof(struct mptsas_hotplug_event));
1970 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1971 ev->ioc = ioc;
1972 ev->id = raid_event_data->VolumeID;
Moore, Ericbd23e942006-04-17 12:43:04 -06001973 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787e2006-01-26 16:20:06 -07001974
1975 switch (raid_event_data->ReasonCode) {
1976 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
1977 ev->event_type = MPTSAS_ADD_DEVICE;
1978 break;
1979 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07001980 ioc->raid_data.isRaid = 1;
1981 ev->phys_disk_num_valid = 1;
1982 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787e2006-01-26 16:20:06 -07001983 ev->event_type = MPTSAS_DEL_DEVICE;
1984 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06001985 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
1986 switch (state) {
1987 case MPI_PD_STATE_ONLINE:
1988 ioc->raid_data.isRaid = 1;
1989 ev->phys_disk_num_valid = 1;
1990 ev->phys_disk_num = raid_event_data->PhysDiskNum;
1991 ev->event_type = MPTSAS_ADD_DEVICE;
1992 break;
1993 case MPI_PD_STATE_MISSING:
1994 case MPI_PD_STATE_NOT_COMPATIBLE:
1995 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
1996 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
1997 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
1998 ev->event_type = MPTSAS_DEL_DEVICE;
1999 break;
2000 default:
2001 break;
2002 }
2003 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07002004 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2005 ev->event_type = MPTSAS_DEL_RAID;
2006 break;
2007 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2008 ev->event_type = MPTSAS_ADD_RAID;
2009 break;
2010 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002011 switch (state) {
2012 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2013 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2014 ev->event_type = MPTSAS_DEL_RAID;
2015 break;
2016 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2017 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2018 ev->event_type = MPTSAS_ADD_RAID;
2019 break;
2020 default:
2021 break;
2022 }
Moore, Ericc73787e2006-01-26 16:20:06 -07002023 break;
2024 default:
2025 break;
2026 }
2027 schedule_work(&ev->work);
2028}
2029
Moore, Erice6b2d762006-03-14 09:14:24 -07002030static void
2031mptscsih_send_discovery(MPT_ADAPTER *ioc,
2032 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2033{
2034 struct mptsas_discovery_event *ev;
2035
2036 /*
2037 * DiscoveryStatus
2038 *
2039 * This flag will be non-zero when firmware
2040 * kicks off discovery, and return to zero
2041 * once its completed.
2042 */
2043 if (discovery_data->DiscoveryStatus)
2044 return;
2045
2046 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
2047 if (!ev)
2048 return;
2049 memset(ev,0,sizeof(struct mptsas_discovery_event));
2050 INIT_WORK(&ev->work, mptscsih_discovery_work, ev);
2051 ev->ioc = ioc;
2052 schedule_work(&ev->work);
2053};
2054
2055
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002056static int
2057mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2058{
Moore, Ericc73787e2006-01-26 16:20:06 -07002059 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002060 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2061
2062 if (!ioc->sh)
Moore, Ericc73787e2006-01-26 16:20:06 -07002063 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002064
Moore, Erice6b2d762006-03-14 09:14:24 -07002065 /*
2066 * sas_discovery_ignore_events
2067 *
2068 * This flag is to prevent anymore processing of
2069 * sas events once mptsas_remove function is called.
2070 */
2071 if (ioc->sas_discovery_ignore_events) {
2072 rc = mptscsih_event_process(ioc, reply);
2073 goto out;
2074 }
2075
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002076 switch (event) {
2077 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
2078 mptscsih_send_sas_event(ioc,
2079 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787e2006-01-26 16:20:06 -07002080 break;
2081 case MPI_EVENT_INTEGRATED_RAID:
2082 mptscsih_send_raid_event(ioc,
2083 (EVENT_DATA_RAID *)reply->Data);
2084 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002085 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2086 INIT_WORK(&ioc->mptscsih_persistTask,
2087 mptscsih_sas_persist_clear_table,
2088 (void *)ioc);
2089 schedule_work(&ioc->mptscsih_persistTask);
2090 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002091 case MPI_EVENT_SAS_DISCOVERY:
Moore, Erice6b2d762006-03-14 09:14:24 -07002092 mptscsih_send_discovery(ioc,
2093 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2094 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002095 default:
Moore, Ericc73787e2006-01-26 16:20:06 -07002096 rc = mptscsih_event_process(ioc, reply);
2097 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002098 }
Moore, Ericc73787e2006-01-26 16:20:06 -07002099 out:
2100
2101 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002102}
2103
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002104static int
2105mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2106{
2107 struct Scsi_Host *sh;
2108 MPT_SCSI_HOST *hd;
2109 MPT_ADAPTER *ioc;
2110 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002111 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002112 int numSGE = 0;
2113 int scale;
2114 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002115 int error=0;
2116 int r;
2117
2118 r = mpt_attach(pdev,id);
2119 if (r)
2120 return r;
2121
2122 ioc = pci_get_drvdata(pdev);
2123 ioc->DoneCtx = mptsasDoneCtx;
2124 ioc->TaskCtx = mptsasTaskCtx;
2125 ioc->InternalCtx = mptsasInternalCtx;
2126
2127 /* Added sanity check on readiness of the MPT adapter.
2128 */
2129 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2130 printk(MYIOC_s_WARN_FMT
2131 "Skipping because it's not operational!\n",
2132 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002133 error = -ENODEV;
2134 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002135 }
2136
2137 if (!ioc->active) {
2138 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2139 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002140 error = -ENODEV;
2141 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002142 }
2143
2144 /* Sanity check - ensure at least 1 port is INITIATOR capable
2145 */
2146 ioc_cap = 0;
2147 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2148 if (ioc->pfacts[ii].ProtocolFlags &
2149 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2150 ioc_cap++;
2151 }
2152
2153 if (!ioc_cap) {
2154 printk(MYIOC_s_WARN_FMT
2155 "Skipping ioc=%p because SCSI Initiator mode "
2156 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002157 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002158 }
2159
2160 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2161 if (!sh) {
2162 printk(MYIOC_s_WARN_FMT
2163 "Unable to register controller with SCSI subsystem\n",
2164 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002165 error = -1;
2166 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002167 }
2168
2169 spin_lock_irqsave(&ioc->FreeQlock, flags);
2170
2171 /* Attach the SCSI Host to the IOC structure
2172 */
2173 ioc->sh = sh;
2174
2175 sh->io_port = 0;
2176 sh->n_io_port = 0;
2177 sh->irq = 0;
2178
2179 /* set 16 byte cdb's */
2180 sh->max_cmd_len = 16;
2181
2182 sh->max_id = ioc->pfacts->MaxDevices + 1;
2183
2184 sh->transportt = mptsas_transport_template;
2185
2186 sh->max_lun = MPT_LAST_LUN + 1;
2187 sh->max_channel = 0;
2188 sh->this_id = ioc->pfacts[0].PortSCSIID;
2189
2190 /* Required entry.
2191 */
2192 sh->unique_id = ioc->id;
2193
2194 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002195 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002196 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002197 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002198 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002199
2200 /* Verify that we won't exceed the maximum
2201 * number of chain buffers
2202 * We can optimize: ZZ = req_sz/sizeof(SGE)
2203 * For 32bit SGE's:
2204 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2205 * + (req_sz - 64)/sizeof(SGE)
2206 * A slightly different algorithm is required for
2207 * 64bit SGEs.
2208 */
2209 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2210 if (sizeof(dma_addr_t) == sizeof(u64)) {
2211 numSGE = (scale - 1) *
2212 (ioc->facts.MaxChainDepth-1) + scale +
2213 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2214 sizeof(u32));
2215 } else {
2216 numSGE = 1 + (scale - 1) *
2217 (ioc->facts.MaxChainDepth-1) + scale +
2218 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2219 sizeof(u32));
2220 }
2221
2222 if (numSGE < sh->sg_tablesize) {
2223 /* Reset this value */
2224 dprintk((MYIOC_s_INFO_FMT
2225 "Resetting sg_tablesize to %d from %d\n",
2226 ioc->name, numSGE, sh->sg_tablesize));
2227 sh->sg_tablesize = numSGE;
2228 }
2229
2230 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2231
2232 hd = (MPT_SCSI_HOST *) sh->hostdata;
2233 hd->ioc = ioc;
2234
2235 /* SCSI needs scsi_cmnd lookup table!
2236 * (with size equal to req_depth*PtrSz!)
2237 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002238 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2239 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002240 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002241 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002242 }
2243
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002244 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2245 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002246
2247 /* Allocate memory for the device structures.
2248 * A non-Null pointer at an offset
2249 * indicates a device exists.
2250 * max_id = 1 + maximum id (hosts.h)
2251 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002252 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
2253 if (!hd->Targets) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002254 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002255 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002256 }
2257
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002258 dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002259
2260 /* Clear the TM flags
2261 */
2262 hd->tmPending = 0;
2263 hd->tmState = TM_STATE_NONE;
2264 hd->resetPending = 0;
2265 hd->abortSCpnt = NULL;
2266
2267 /* Clear the pointer used to store
2268 * single-threaded commands, i.e., those
2269 * issued during a bus scan, dv and
2270 * configuration pages.
2271 */
2272 hd->cmdPtr = NULL;
2273
2274 /* Initialize this SCSI Hosts' timers
2275 * To use, set the timer expires field
2276 * and add_timer
2277 */
2278 init_timer(&hd->timer);
2279 hd->timer.data = (unsigned long) hd;
2280 hd->timer.function = mptscsih_timer_expired;
2281
2282 hd->mpt_pq_filter = mpt_pq_filter;
2283 ioc->sas_data.ptClear = mpt_pt_clear;
2284
2285 if (ioc->sas_data.ptClear==1) {
2286 mptbase_sas_persist_operation(
2287 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2288 }
2289
2290 ddvprintk((MYIOC_s_INFO_FMT
2291 "mpt_pq_filter %x mpt_pq_filter %x\n",
2292 ioc->name,
2293 mpt_pq_filter,
2294 mpt_pq_filter));
2295
2296 init_waitqueue_head(&hd->scandv_waitq);
2297 hd->scandv_wait_done = 0;
2298 hd->last_queue_full = 0;
2299
2300 error = scsi_add_host(sh, &ioc->pcidev->dev);
2301 if (error) {
2302 dprintk((KERN_ERR MYNAM
2303 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002304 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002305 }
2306
2307 mptsas_scan_sas_topology(ioc);
2308
2309 return 0;
2310
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002311out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002312
2313 mptscsih_remove(pdev);
2314 return error;
2315}
2316
2317static void __devexit mptsas_remove(struct pci_dev *pdev)
2318{
2319 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2320 struct mptsas_portinfo *p, *n;
2321
Moore, Erice6b2d762006-03-14 09:14:24 -07002322 ioc->sas_discovery_ignore_events=1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002323 sas_remove_host(ioc->sh);
2324
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002325 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002326 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2327 list_del(&p->list);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002328 if (p->phy_info)
2329 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 kfree(p);
2331 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002332 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002333
2334 mptscsih_remove(pdev);
2335}
2336
2337static struct pci_device_id mptsas_pci_table[] = {
2338 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
2339 PCI_ANY_ID, PCI_ANY_ID },
2340 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
2341 PCI_ANY_ID, PCI_ANY_ID },
2342 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
2343 PCI_ANY_ID, PCI_ANY_ID },
2344 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
2345 PCI_ANY_ID, PCI_ANY_ID },
2346 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
2347 PCI_ANY_ID, PCI_ANY_ID },
2348 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
2349 PCI_ANY_ID, PCI_ANY_ID },
2350 {0} /* Terminating entry */
2351};
2352MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2353
2354
2355static struct pci_driver mptsas_driver = {
2356 .name = "mptsas",
2357 .id_table = mptsas_pci_table,
2358 .probe = mptsas_probe,
2359 .remove = __devexit_p(mptsas_remove),
2360 .shutdown = mptscsih_shutdown,
2361#ifdef CONFIG_PM
2362 .suspend = mptscsih_suspend,
2363 .resume = mptscsih_resume,
2364#endif
2365};
2366
2367static int __init
2368mptsas_init(void)
2369{
2370 show_mptmod_ver(my_NAME, my_VERSION);
2371
2372 mptsas_transport_template =
2373 sas_attach_transport(&mptsas_transport_functions);
2374 if (!mptsas_transport_template)
2375 return -ENODEV;
2376
2377 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
2378 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
2379 mptsasInternalCtx =
2380 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002381 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002382
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002383 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07002384 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002385 ": Registered for IOC event notifications\n"));
2386 }
2387
2388 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
2389 dprintk((KERN_INFO MYNAM
2390 ": Registered for IOC reset notifications\n"));
2391 }
2392
2393 return pci_register_driver(&mptsas_driver);
2394}
2395
2396static void __exit
2397mptsas_exit(void)
2398{
2399 pci_unregister_driver(&mptsas_driver);
2400 sas_release_transport(mptsas_transport_template);
2401
2402 mpt_reset_deregister(mptsasDoneCtx);
2403 mpt_event_deregister(mptsasDoneCtx);
2404
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002405 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002406 mpt_deregister(mptsasInternalCtx);
2407 mpt_deregister(mptsasTaskCtx);
2408 mpt_deregister(mptsasDoneCtx);
2409}
2410
2411module_init(mptsas_init);
2412module_exit(mptsas_exit);