blob: af6ec553ff7ca54c3cf4ee14c7e43e32cd9e73a2 [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,
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, Ericc73787ee2006-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, Ericc73787ee2006-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:
Moore, Erice6b2d762006-03-14 09:14:24 -07001381 if (hba)
1382 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001383 out:
1384 return error;
1385}
1386
1387static int
Moore, Erice6b2d762006-03-14 09:14:24 -07001388mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001389{
Moore, Erice6b2d762006-03-14 09:14:24 -07001390 struct mptsas_portinfo *port_info, *p, *ex;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001391 int error = -ENOMEM, i, j;
1392
Moore, Erice6b2d762006-03-14 09:14:24 -07001393 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
1394 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001395 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001396
Moore, Erice6b2d762006-03-14 09:14:24 -07001397 error = mptsas_sas_expander_pg0(ioc, ex,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001398 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
1399 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
1400 if (error)
1401 goto out_free_port_info;
1402
Moore, Erice6b2d762006-03-14 09:14:24 -07001403 *handle = ex->handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001404
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001405 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07001406 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
1407 if (!port_info) {
1408 port_info = ex;
1409 list_add_tail(&port_info->list, &ioc->sas_topology);
1410 } else {
1411 port_info->handle = ex->handle;
1412 if (ex->phy_info)
1413 kfree(ex->phy_info);
1414 kfree(ex);
1415 ex = NULL;
1416 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001417 mutex_unlock(&ioc->sas_topology_mutex);
1418
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001419 for (i = 0; i < port_info->num_phys; i++) {
1420 struct device *parent;
1421
1422 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
1423 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
1424 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
1425
1426 if (port_info->phy_info[i].identify.handle) {
1427 mptsas_sas_device_pg0(ioc,
1428 &port_info->phy_info[i].identify,
1429 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1430 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1431 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02001432 port_info->phy_info[i].identify.phy_id =
1433 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001434 }
1435
1436 if (port_info->phy_info[i].attached.handle) {
1437 mptsas_sas_device_pg0(ioc,
1438 &port_info->phy_info[i].attached,
1439 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1440 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1441 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07001442 port_info->phy_info[i].attached.phy_id =
1443 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001444 }
1445
1446 /*
1447 * If we find a parent port handle this expander is
1448 * attached to another expander, else it hangs of the
1449 * HBA phys.
1450 */
1451 parent = &ioc->sh->shost_gendev;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001452 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001453 list_for_each_entry(p, &ioc->sas_topology, list) {
1454 for (j = 0; j < p->num_phys; j++) {
1455 if (port_info->phy_info[i].identify.handle ==
1456 p->phy_info[j].attached.handle)
1457 parent = &p->phy_info[j].rphy->dev;
1458 }
1459 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001460 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001461
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001462 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07001463 ioc->sas_index, 0);
1464 ioc->sas_index++;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001465 }
1466
1467 return 0;
1468
1469 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07001470 if (ex) {
1471 if (ex->phy_info)
1472 kfree(ex->phy_info);
1473 kfree(ex);
1474 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001475 out:
1476 return error;
1477}
1478
Moore, Erice6b2d762006-03-14 09:14:24 -07001479/*
1480 * mptsas_delete_expander_phys
1481 *
1482 *
1483 * This will traverse topology, and remove expanders
1484 * that are no longer present
1485 */
1486static void
1487mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
1488{
1489 struct mptsas_portinfo buffer;
1490 struct mptsas_portinfo *port_info, *n, *parent;
1491 int i;
1492
1493 mutex_lock(&ioc->sas_topology_mutex);
1494 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
1495
1496 if (port_info->phy_info &&
1497 (!(port_info->phy_info[0].identify.device_info &
1498 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
1499 continue;
1500
1501 if (mptsas_sas_expander_pg0(ioc, &buffer,
1502 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
1503 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
1504
1505 /*
1506 * Obtain the port_info instance to the parent port
1507 */
1508 parent = mptsas_find_portinfo_by_handle(ioc,
1509 port_info->phy_info[0].identify.handle_parent);
1510
1511 if (!parent)
1512 goto next_port;
1513
1514 /*
1515 * Delete rphys in the parent that point
1516 * to this expander. The transport layer will
1517 * cleanup all the children.
1518 */
1519 for (i = 0; i < parent->num_phys; i++) {
1520 if ((!parent->phy_info[i].rphy) ||
1521 (parent->phy_info[i].attached.sas_address !=
1522 port_info->phy_info[i].identify.sas_address))
1523 continue;
1524 sas_rphy_delete(parent->phy_info[i].rphy);
1525 memset(&parent->phy_info[i].attached, 0,
1526 sizeof(struct mptsas_devinfo));
1527 parent->phy_info[i].rphy = NULL;
1528 parent->phy_info[i].starget = NULL;
1529 }
1530 next_port:
1531 list_del(&port_info->list);
1532 if (port_info->phy_info)
1533 kfree(port_info->phy_info);
1534 kfree(port_info);
1535 }
1536 /*
1537 * Free this memory allocated from inside
1538 * mptsas_sas_expander_pg0
1539 */
1540 if (buffer.phy_info)
1541 kfree(buffer.phy_info);
1542 }
1543 mutex_unlock(&ioc->sas_topology_mutex);
1544}
1545
1546/*
1547 * Start of day discovery
1548 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001549static void
1550mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
1551{
1552 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07001553 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001554
Moore, Erice6b2d762006-03-14 09:14:24 -07001555 mutex_lock(&ioc->sas_discovery_mutex);
1556 mptsas_probe_hba_phys(ioc);
1557 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001558 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07001559 /*
1560 Reporting RAID volumes.
1561 */
1562 if (!ioc->raid_data.pIocPg2)
1563 goto out;
1564 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
1565 goto out;
1566 for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1567 scsi_add_device(ioc->sh, ioc->num_ports,
1568 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
1569 }
1570 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07001571 mutex_unlock(&ioc->sas_discovery_mutex);
1572}
1573
1574/*
1575 * Work queue thread to handle Runtime discovery
1576 * Mere purpose is the hot add/delete of expanders
1577 */
1578static void
1579mptscsih_discovery_work(void * arg)
1580{
1581 struct mptsas_discovery_event *ev = arg;
1582 MPT_ADAPTER *ioc = ev->ioc;
1583 u32 handle = 0xFFFF;
1584
1585 mutex_lock(&ioc->sas_discovery_mutex);
1586 ioc->sas_discovery_runtime=1;
1587 mptsas_delete_expander_phys(ioc);
1588 mptsas_probe_hba_phys(ioc);
1589 while (!mptsas_probe_expander_phys(ioc, &handle))
1590 ;
1591 kfree(ev);
1592 ioc->sas_discovery_runtime=0;
1593 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001594}
1595
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001596static struct mptsas_phyinfo *
1597mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
1598{
1599 struct mptsas_portinfo *port_info;
1600 struct mptsas_devinfo device_info;
1601 struct mptsas_phyinfo *phy_info = NULL;
1602 int i, error;
1603
1604 /*
1605 * Retrieve the parent sas_address
1606 */
1607 error = mptsas_sas_device_pg0(ioc, &device_info,
1608 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
1609 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
1610 parent_handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07001611 if (error)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001612 return NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001613
1614 /*
1615 * The phy_info structures are never deallocated during lifetime of
1616 * a host, so the code below is safe without additional refcounting.
1617 */
1618 mutex_lock(&ioc->sas_topology_mutex);
1619 list_for_each_entry(port_info, &ioc->sas_topology, list) {
1620 for (i = 0; i < port_info->num_phys; i++) {
1621 if (port_info->phy_info[i].identify.sas_address ==
1622 device_info.sas_address &&
1623 port_info->phy_info[i].phy_id == phy_id) {
1624 phy_info = &port_info->phy_info[i];
1625 break;
1626 }
1627 }
1628 }
1629 mutex_unlock(&ioc->sas_topology_mutex);
1630
1631 return phy_info;
1632}
1633
1634static struct mptsas_phyinfo *
Moore, Ericc73787ee2006-01-26 16:20:06 -07001635mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001636{
1637 struct mptsas_portinfo *port_info;
1638 struct mptsas_phyinfo *phy_info = NULL;
1639 int i;
1640
1641 /*
1642 * The phy_info structures are never deallocated during lifetime of
1643 * a host, so the code below is safe without additional refcounting.
1644 */
1645 mutex_lock(&ioc->sas_topology_mutex);
1646 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Moore, Ericc73787ee2006-01-26 16:20:06 -07001647 for (i = 0; i < port_info->num_phys; i++)
1648 if (mptsas_is_end_device(&port_info->phy_info[i].attached))
1649 if (port_info->phy_info[i].attached.id == id) {
1650 phy_info = &port_info->phy_info[i];
1651 break;
1652 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001653 }
1654 mutex_unlock(&ioc->sas_topology_mutex);
1655
1656 return phy_info;
1657}
1658
Moore, Eric4b766472006-03-14 09:14:12 -07001659/*
1660 * Work queue thread to clear the persitency table
1661 */
1662static void
1663mptscsih_sas_persist_clear_table(void * arg)
1664{
1665 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
1666
1667 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
1668}
1669
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001670static void
Moore, Ericf44e5462006-03-14 09:14:21 -07001671mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
1672{
1673 sdev->no_uld_attach = data ? 1 : 0;
1674 scsi_device_reprobe(sdev);
1675}
1676
1677static void
1678mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
1679{
1680 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
1681 mptsas_reprobe_lun);
1682}
1683
Moore, Erice6b2d762006-03-14 09:14:24 -07001684
1685/*
1686 * Work queue thread to handle SAS hotplug events
1687 */
Moore, Ericf44e5462006-03-14 09:14:21 -07001688static void
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001689mptsas_hotplug_work(void *arg)
1690{
1691 struct mptsas_hotplug_event *ev = arg;
1692 MPT_ADAPTER *ioc = ev->ioc;
1693 struct mptsas_phyinfo *phy_info;
1694 struct sas_rphy *rphy;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001695 struct scsi_device *sdev;
James Bottomleyf013db32006-03-18 14:54:36 -06001696 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001697 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001698 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07001699 VirtTarget *vtarget;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001700
Moore, Erice6b2d762006-03-14 09:14:24 -07001701 mutex_lock(&ioc->sas_discovery_mutex);
1702
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001703 switch (ev->event_type) {
1704 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001705
Moore, Ericc73787ee2006-01-26 16:20:06 -07001706 phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001707
Moore, Ericf44e5462006-03-14 09:14:21 -07001708 /*
1709 * Sanity checks, for non-existing phys and remote rphys.
1710 */
1711 if (!phy_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001712 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07001713 if (!phy_info->rphy)
1714 break;
1715 if (phy_info->starget) {
1716 vtarget = phy_info->starget->hostdata;
1717
1718 if (!vtarget)
1719 break;
1720 /*
1721 * Handling RAID components
1722 */
1723 if (ev->phys_disk_num_valid) {
1724 vtarget->target_id = ev->phys_disk_num;
1725 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
1726 mptsas_reprobe_target(vtarget->starget, 1);
1727 break;
1728 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001729 }
1730
Moore, Ericc73787ee2006-01-26 16:20:06 -07001731 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1732 ds = "ssp";
1733 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1734 ds = "stp";
1735 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1736 ds = "sata";
1737
1738 printk(MYIOC_s_INFO_FMT
1739 "removing %s device, channel %d, id %d, phy %d\n",
1740 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
1741
Moore, Ericf44e5462006-03-14 09:14:21 -07001742 sas_rphy_delete(phy_info->rphy);
1743 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
1744 phy_info->rphy = NULL;
1745 phy_info->starget = NULL;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001746 break;
1747 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07001748
Moore, Ericbd23e942006-04-17 12:43:04 -06001749 if (ev->phys_disk_num_valid)
1750 mpt_findImVolumes(ioc);
1751
Moore, Ericc73787ee2006-01-26 16:20:06 -07001752 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01001753 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07001754 */
Christoph Hellwige3094442006-02-16 13:25:36 +01001755 if (mptsas_sas_device_pg0(ioc, &sas_device,
1756 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
1757 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
1758 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001759
1760 phy_info = mptsas_find_phyinfo_by_parent(ioc,
Christoph Hellwige3094442006-02-16 13:25:36 +01001761 sas_device.handle_parent, sas_device.phy_id);
Moore, Erice6b2d762006-03-14 09:14:24 -07001762
1763 if (!phy_info) {
1764 u32 handle = 0xFFFF;
1765
1766 /*
1767 * Its possible when an expander has been hot added
1768 * containing attached devices, the sas firmware
1769 * may send a RC_ADDED event prior to the
1770 * DISCOVERY STOP event. If that occurs, our
1771 * view of the topology in the driver in respect to this
1772 * expander might of not been setup, and we hit this
1773 * condition.
1774 * Therefore, this code kicks off discovery to
1775 * refresh the data.
1776 * Then again, we check whether the parent phy has
1777 * been created.
1778 */
1779 ioc->sas_discovery_runtime=1;
1780 mptsas_delete_expander_phys(ioc);
1781 mptsas_probe_hba_phys(ioc);
1782 while (!mptsas_probe_expander_phys(ioc, &handle))
1783 ;
1784 ioc->sas_discovery_runtime=0;
1785
1786 phy_info = mptsas_find_phyinfo_by_parent(ioc,
1787 sas_device.handle_parent, sas_device.phy_id);
1788 if (!phy_info)
1789 break;
1790 }
1791
Moore, Ericf44e5462006-03-14 09:14:21 -07001792 if (phy_info->starget) {
1793 vtarget = phy_info->starget->hostdata;
1794
1795 if (!vtarget)
1796 break;
1797 /*
1798 * Handling RAID components
1799 */
1800 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
1801 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
1802 vtarget->target_id = ev->id;
1803 mptsas_reprobe_target(phy_info->starget, 0);
1804 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001805 break;
1806 }
1807
Moore, Ericf44e5462006-03-14 09:14:21 -07001808 if (phy_info->rphy)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001809 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001810
Christoph Hellwige3094442006-02-16 13:25:36 +01001811 memcpy(&phy_info->attached, &sas_device,
1812 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001813
Moore, Ericc73787ee2006-01-26 16:20:06 -07001814 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1815 ds = "ssp";
1816 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
1817 ds = "stp";
1818 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1819 ds = "sata";
1820
1821 printk(MYIOC_s_INFO_FMT
1822 "attaching %s device, channel %d, id %d, phy %d\n",
1823 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
1824
James Bottomleyf013db32006-03-18 14:54:36 -06001825 mptsas_parse_device_info(&identify, &phy_info->attached);
1826 switch (identify.device_type) {
1827 case SAS_END_DEVICE:
1828 rphy = sas_end_device_alloc(phy_info->phy);
1829 break;
1830 case SAS_EDGE_EXPANDER_DEVICE:
1831 case SAS_FANOUT_EXPANDER_DEVICE:
1832 rphy = sas_expander_alloc(phy_info->phy, identify.device_type);
1833 break;
1834 default:
1835 rphy = NULL;
1836 break;
1837 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001838 if (!rphy)
1839 break; /* non-fatal: an rphy can be added later */
1840
James Bottomleyf013db32006-03-18 14:54:36 -06001841 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001842 if (sas_rphy_add(rphy)) {
1843 sas_rphy_free(rphy);
1844 break;
1845 }
1846
1847 phy_info->rphy = rphy;
1848 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001849 case MPTSAS_ADD_RAID:
1850 sdev = scsi_device_lookup(
1851 ioc->sh,
1852 ioc->num_ports,
1853 ev->id,
1854 0);
1855 if (sdev) {
1856 scsi_device_put(sdev);
1857 break;
1858 }
1859 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001860 "attaching raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001861 ioc->name, ioc->num_ports, ev->id);
1862 scsi_add_device(ioc->sh,
1863 ioc->num_ports,
1864 ev->id,
1865 0);
1866 mpt_findImVolumes(ioc);
1867 break;
1868 case MPTSAS_DEL_RAID:
1869 sdev = scsi_device_lookup(
1870 ioc->sh,
1871 ioc->num_ports,
1872 ev->id,
1873 0);
1874 if (!sdev)
1875 break;
1876 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07001877 "removing raid volume, channel %d, id %d\n",
Moore, Ericc73787ee2006-01-26 16:20:06 -07001878 ioc->name, ioc->num_ports, ev->id);
1879 scsi_remove_device(sdev);
1880 scsi_device_put(sdev);
1881 mpt_findImVolumes(ioc);
1882 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06001883 case MPTSAS_IGNORE_EVENT:
1884 default:
1885 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001886 }
1887
1888 kfree(ev);
Moore, Erice6b2d762006-03-14 09:14:24 -07001889 mutex_unlock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890}
1891
1892static void
1893mptscsih_send_sas_event(MPT_ADAPTER *ioc,
1894 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1895{
1896 struct mptsas_hotplug_event *ev;
1897 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
1898 __le64 sas_address;
1899
1900 if ((device_info &
1901 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
1902 MPI_SAS_DEVICE_INFO_STP_TARGET |
1903 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
1904 return;
1905
Moore, Eric4b766472006-03-14 09:14:12 -07001906 switch (sas_event_data->ReasonCode) {
1907 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
1908 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
1909 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1910 if (!ev) {
1911 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1912 break;
1913 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001914
Moore, Eric4b766472006-03-14 09:14:12 -07001915 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1916 ev->ioc = ioc;
1917 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
1918 ev->parent_handle =
1919 le16_to_cpu(sas_event_data->ParentDevHandle);
1920 ev->channel = sas_event_data->Bus;
1921 ev->id = sas_event_data->TargetID;
1922 ev->phy_id = sas_event_data->PhyNum;
1923 memcpy(&sas_address, &sas_event_data->SASAddress,
1924 sizeof(__le64));
1925 ev->sas_address = le64_to_cpu(sas_address);
1926 ev->device_info = device_info;
1927
1928 if (sas_event_data->ReasonCode &
1929 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
1930 ev->event_type = MPTSAS_ADD_DEVICE;
1931 else
1932 ev->event_type = MPTSAS_DEL_DEVICE;
1933 schedule_work(&ev->work);
1934 break;
1935 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
1936 /*
1937 * Persistent table is full.
1938 */
1939 INIT_WORK(&ioc->mptscsih_persistTask,
1940 mptscsih_sas_persist_clear_table,
1941 (void *)ioc);
1942 schedule_work(&ioc->mptscsih_persistTask);
1943 break;
1944 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
1945 /* TODO */
1946 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
1947 /* TODO */
1948 default:
1949 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001950 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001951}
1952
Moore, Ericc73787ee2006-01-26 16:20:06 -07001953static void
1954mptscsih_send_raid_event(MPT_ADAPTER *ioc,
1955 EVENT_DATA_RAID *raid_event_data)
1956{
1957 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06001958 int status = le32_to_cpu(raid_event_data->SettingsStatus);
1959 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001960
1961 if (ioc->bus_type != SAS)
1962 return;
1963
1964 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
1965 if (!ev) {
1966 printk(KERN_WARNING "mptsas: lost hotplug event\n");
1967 return;
1968 }
1969
1970 memset(ev,0,sizeof(struct mptsas_hotplug_event));
1971 INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
1972 ev->ioc = ioc;
1973 ev->id = raid_event_data->VolumeID;
Moore, Ericbd23e942006-04-17 12:43:04 -06001974 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001975
1976 switch (raid_event_data->ReasonCode) {
1977 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
1978 ev->event_type = MPTSAS_ADD_DEVICE;
1979 break;
1980 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07001981 ioc->raid_data.isRaid = 1;
1982 ev->phys_disk_num_valid = 1;
1983 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07001984 ev->event_type = MPTSAS_DEL_DEVICE;
1985 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06001986 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
1987 switch (state) {
1988 case MPI_PD_STATE_ONLINE:
1989 ioc->raid_data.isRaid = 1;
1990 ev->phys_disk_num_valid = 1;
1991 ev->phys_disk_num = raid_event_data->PhysDiskNum;
1992 ev->event_type = MPTSAS_ADD_DEVICE;
1993 break;
1994 case MPI_PD_STATE_MISSING:
1995 case MPI_PD_STATE_NOT_COMPATIBLE:
1996 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
1997 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
1998 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
1999 ev->event_type = MPTSAS_DEL_DEVICE;
2000 break;
2001 default:
2002 break;
2003 }
2004 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002005 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2006 ev->event_type = MPTSAS_DEL_RAID;
2007 break;
2008 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2009 ev->event_type = MPTSAS_ADD_RAID;
2010 break;
2011 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002012 switch (state) {
2013 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2014 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2015 ev->event_type = MPTSAS_DEL_RAID;
2016 break;
2017 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2018 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2019 ev->event_type = MPTSAS_ADD_RAID;
2020 break;
2021 default:
2022 break;
2023 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002024 break;
2025 default:
2026 break;
2027 }
2028 schedule_work(&ev->work);
2029}
2030
Moore, Erice6b2d762006-03-14 09:14:24 -07002031static void
2032mptscsih_send_discovery(MPT_ADAPTER *ioc,
2033 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2034{
2035 struct mptsas_discovery_event *ev;
2036
2037 /*
2038 * DiscoveryStatus
2039 *
2040 * This flag will be non-zero when firmware
2041 * kicks off discovery, and return to zero
2042 * once its completed.
2043 */
2044 if (discovery_data->DiscoveryStatus)
2045 return;
2046
2047 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
2048 if (!ev)
2049 return;
2050 memset(ev,0,sizeof(struct mptsas_discovery_event));
2051 INIT_WORK(&ev->work, mptscsih_discovery_work, ev);
2052 ev->ioc = ioc;
2053 schedule_work(&ev->work);
2054};
2055
2056
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002057static int
2058mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
2059{
Moore, Ericc73787ee2006-01-26 16:20:06 -07002060 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002061 u8 event = le32_to_cpu(reply->Event) & 0xFF;
2062
2063 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002064 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002065
Moore, Erice6b2d762006-03-14 09:14:24 -07002066 /*
2067 * sas_discovery_ignore_events
2068 *
2069 * This flag is to prevent anymore processing of
2070 * sas events once mptsas_remove function is called.
2071 */
2072 if (ioc->sas_discovery_ignore_events) {
2073 rc = mptscsih_event_process(ioc, reply);
2074 goto out;
2075 }
2076
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002077 switch (event) {
2078 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
2079 mptscsih_send_sas_event(ioc,
2080 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002081 break;
2082 case MPI_EVENT_INTEGRATED_RAID:
2083 mptscsih_send_raid_event(ioc,
2084 (EVENT_DATA_RAID *)reply->Data);
2085 break;
Moore, Eric79de2782006-01-25 18:05:15 -07002086 case MPI_EVENT_PERSISTENT_TABLE_FULL:
2087 INIT_WORK(&ioc->mptscsih_persistTask,
2088 mptscsih_sas_persist_clear_table,
2089 (void *)ioc);
2090 schedule_work(&ioc->mptscsih_persistTask);
2091 break;
Moore, Eric4b766472006-03-14 09:14:12 -07002092 case MPI_EVENT_SAS_DISCOVERY:
Moore, Erice6b2d762006-03-14 09:14:24 -07002093 mptscsih_send_discovery(ioc,
2094 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
2095 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002096 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002097 rc = mptscsih_event_process(ioc, reply);
2098 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002099 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002100 out:
2101
2102 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002103}
2104
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002105static int
2106mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
2107{
2108 struct Scsi_Host *sh;
2109 MPT_SCSI_HOST *hd;
2110 MPT_ADAPTER *ioc;
2111 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002112 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002113 int numSGE = 0;
2114 int scale;
2115 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002116 int error=0;
2117 int r;
2118
2119 r = mpt_attach(pdev,id);
2120 if (r)
2121 return r;
2122
2123 ioc = pci_get_drvdata(pdev);
2124 ioc->DoneCtx = mptsasDoneCtx;
2125 ioc->TaskCtx = mptsasTaskCtx;
2126 ioc->InternalCtx = mptsasInternalCtx;
2127
2128 /* Added sanity check on readiness of the MPT adapter.
2129 */
2130 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
2131 printk(MYIOC_s_WARN_FMT
2132 "Skipping because it's not operational!\n",
2133 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002134 error = -ENODEV;
2135 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002136 }
2137
2138 if (!ioc->active) {
2139 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
2140 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002141 error = -ENODEV;
2142 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002143 }
2144
2145 /* Sanity check - ensure at least 1 port is INITIATOR capable
2146 */
2147 ioc_cap = 0;
2148 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
2149 if (ioc->pfacts[ii].ProtocolFlags &
2150 MPI_PORTFACTS_PROTOCOL_INITIATOR)
2151 ioc_cap++;
2152 }
2153
2154 if (!ioc_cap) {
2155 printk(MYIOC_s_WARN_FMT
2156 "Skipping ioc=%p because SCSI Initiator mode "
2157 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002158 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002159 }
2160
2161 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
2162 if (!sh) {
2163 printk(MYIOC_s_WARN_FMT
2164 "Unable to register controller with SCSI subsystem\n",
2165 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002166 error = -1;
2167 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002168 }
2169
2170 spin_lock_irqsave(&ioc->FreeQlock, flags);
2171
2172 /* Attach the SCSI Host to the IOC structure
2173 */
2174 ioc->sh = sh;
2175
2176 sh->io_port = 0;
2177 sh->n_io_port = 0;
2178 sh->irq = 0;
2179
2180 /* set 16 byte cdb's */
2181 sh->max_cmd_len = 16;
2182
2183 sh->max_id = ioc->pfacts->MaxDevices + 1;
2184
2185 sh->transportt = mptsas_transport_template;
2186
2187 sh->max_lun = MPT_LAST_LUN + 1;
2188 sh->max_channel = 0;
2189 sh->this_id = ioc->pfacts[0].PortSCSIID;
2190
2191 /* Required entry.
2192 */
2193 sh->unique_id = ioc->id;
2194
2195 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002196 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002197 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002198 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002199 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002200
2201 /* Verify that we won't exceed the maximum
2202 * number of chain buffers
2203 * We can optimize: ZZ = req_sz/sizeof(SGE)
2204 * For 32bit SGE's:
2205 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
2206 * + (req_sz - 64)/sizeof(SGE)
2207 * A slightly different algorithm is required for
2208 * 64bit SGEs.
2209 */
2210 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
2211 if (sizeof(dma_addr_t) == sizeof(u64)) {
2212 numSGE = (scale - 1) *
2213 (ioc->facts.MaxChainDepth-1) + scale +
2214 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
2215 sizeof(u32));
2216 } else {
2217 numSGE = 1 + (scale - 1) *
2218 (ioc->facts.MaxChainDepth-1) + scale +
2219 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
2220 sizeof(u32));
2221 }
2222
2223 if (numSGE < sh->sg_tablesize) {
2224 /* Reset this value */
2225 dprintk((MYIOC_s_INFO_FMT
2226 "Resetting sg_tablesize to %d from %d\n",
2227 ioc->name, numSGE, sh->sg_tablesize));
2228 sh->sg_tablesize = numSGE;
2229 }
2230
2231 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
2232
2233 hd = (MPT_SCSI_HOST *) sh->hostdata;
2234 hd->ioc = ioc;
2235
2236 /* SCSI needs scsi_cmnd lookup table!
2237 * (with size equal to req_depth*PtrSz!)
2238 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002239 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
2240 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002241 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002242 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002243 }
2244
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002245 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
2246 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002247
2248 /* Allocate memory for the device structures.
2249 * A non-Null pointer at an offset
2250 * indicates a device exists.
2251 * max_id = 1 + maximum id (hosts.h)
2252 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002253 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
2254 if (!hd->Targets) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002255 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002256 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002257 }
2258
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01002259 dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002260
2261 /* Clear the TM flags
2262 */
2263 hd->tmPending = 0;
2264 hd->tmState = TM_STATE_NONE;
2265 hd->resetPending = 0;
2266 hd->abortSCpnt = NULL;
2267
2268 /* Clear the pointer used to store
2269 * single-threaded commands, i.e., those
2270 * issued during a bus scan, dv and
2271 * configuration pages.
2272 */
2273 hd->cmdPtr = NULL;
2274
2275 /* Initialize this SCSI Hosts' timers
2276 * To use, set the timer expires field
2277 * and add_timer
2278 */
2279 init_timer(&hd->timer);
2280 hd->timer.data = (unsigned long) hd;
2281 hd->timer.function = mptscsih_timer_expired;
2282
2283 hd->mpt_pq_filter = mpt_pq_filter;
2284 ioc->sas_data.ptClear = mpt_pt_clear;
2285
2286 if (ioc->sas_data.ptClear==1) {
2287 mptbase_sas_persist_operation(
2288 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
2289 }
2290
2291 ddvprintk((MYIOC_s_INFO_FMT
2292 "mpt_pq_filter %x mpt_pq_filter %x\n",
2293 ioc->name,
2294 mpt_pq_filter,
2295 mpt_pq_filter));
2296
2297 init_waitqueue_head(&hd->scandv_waitq);
2298 hd->scandv_wait_done = 0;
2299 hd->last_queue_full = 0;
2300
2301 error = scsi_add_host(sh, &ioc->pcidev->dev);
2302 if (error) {
2303 dprintk((KERN_ERR MYNAM
2304 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002305 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002306 }
2307
2308 mptsas_scan_sas_topology(ioc);
2309
2310 return 0;
2311
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07002312out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002313
2314 mptscsih_remove(pdev);
2315 return error;
2316}
2317
2318static void __devexit mptsas_remove(struct pci_dev *pdev)
2319{
2320 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2321 struct mptsas_portinfo *p, *n;
2322
Moore, Erice6b2d762006-03-14 09:14:24 -07002323 ioc->sas_discovery_ignore_events=1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002324 sas_remove_host(ioc->sh);
2325
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002326 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002327 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
2328 list_del(&p->list);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002329 if (p->phy_info)
2330 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002331 kfree(p);
2332 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002333 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002334
2335 mptscsih_remove(pdev);
2336}
2337
2338static struct pci_device_id mptsas_pci_table[] = {
2339 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
2340 PCI_ANY_ID, PCI_ANY_ID },
2341 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
2342 PCI_ANY_ID, PCI_ANY_ID },
2343 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
2344 PCI_ANY_ID, PCI_ANY_ID },
2345 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
2346 PCI_ANY_ID, PCI_ANY_ID },
2347 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
2348 PCI_ANY_ID, PCI_ANY_ID },
2349 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
2350 PCI_ANY_ID, PCI_ANY_ID },
2351 {0} /* Terminating entry */
2352};
2353MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
2354
2355
2356static struct pci_driver mptsas_driver = {
2357 .name = "mptsas",
2358 .id_table = mptsas_pci_table,
2359 .probe = mptsas_probe,
2360 .remove = __devexit_p(mptsas_remove),
2361 .shutdown = mptscsih_shutdown,
2362#ifdef CONFIG_PM
2363 .suspend = mptscsih_suspend,
2364 .resume = mptscsih_resume,
2365#endif
2366};
2367
2368static int __init
2369mptsas_init(void)
2370{
2371 show_mptmod_ver(my_NAME, my_VERSION);
2372
2373 mptsas_transport_template =
2374 sas_attach_transport(&mptsas_transport_functions);
2375 if (!mptsas_transport_template)
2376 return -ENODEV;
2377
2378 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
2379 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
2380 mptsasInternalCtx =
2381 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002382 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002383
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002384 if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
Moore, Eric3a892be2006-03-14 09:14:03 -07002385 devtverboseprintk((KERN_INFO MYNAM
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002386 ": Registered for IOC event notifications\n"));
2387 }
2388
2389 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
2390 dprintk((KERN_INFO MYNAM
2391 ": Registered for IOC reset notifications\n"));
2392 }
2393
2394 return pci_register_driver(&mptsas_driver);
2395}
2396
2397static void __exit
2398mptsas_exit(void)
2399{
2400 pci_unregister_driver(&mptsas_driver);
2401 sas_release_transport(mptsas_transport_template);
2402
2403 mpt_reset_deregister(mptsasDoneCtx);
2404 mpt_event_deregister(mptsasDoneCtx);
2405
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002406 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002407 mpt_deregister(mptsasInternalCtx);
2408 mpt_deregister(mptsasTaskCtx);
2409 mpt_deregister(mptsasDoneCtx);
2410}
2411
2412module_init(mptsas_init);
2413module_exit(mptsas_exit);