blob: 0d9a192e1bd46ce82bef9ae7886cbb0d60bfbce5 [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)
8 * Copyright (c) 2005 Dell
9 */
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 */
86
87
88/*
89 * SAS topology structures
90 *
91 * The MPT Fusion firmware interface spreads information about the
92 * SAS topology over many manufacture pages, thus we need some data
93 * structure to collect it and process it for the SAS transport class.
94 */
95
96struct mptsas_devinfo {
97 u16 handle; /* unique id to address this device */
98 u8 phy_id; /* phy number of parent device */
99 u8 port_id; /* sas physical port this device
100 is assoc'd with */
101 u8 target; /* logical target id of this device */
102 u8 bus; /* logical bus number of this device */
103 u64 sas_address; /* WWN of this device,
104 SATA is assigned by HBA,expander */
105 u32 device_info; /* bitfield detailed info about this device */
106};
107
108struct mptsas_phyinfo {
109 u8 phy_id; /* phy index */
110 u8 port_id; /* port number this phy is part of */
111 u8 negotiated_link_rate; /* nego'd link rate for this phy */
112 u8 hw_link_rate; /* hardware max/min phys link rate */
113 u8 programmed_link_rate; /* programmed max/min phy link rate */
114 struct mptsas_devinfo identify; /* point to phy device info */
115 struct mptsas_devinfo attached; /* point to attached device info */
116 struct sas_rphy *rphy;
117};
118
119struct mptsas_portinfo {
120 struct list_head list;
121 u16 handle; /* unique id to address this */
122 u8 num_phys; /* number of phys */
123 struct mptsas_phyinfo *phy_info;
124};
125
126/*
127 * This is pretty ugly. We will be able to seriously clean it up
128 * once the DV code in mptscsih goes away and we can properly
129 * implement ->target_alloc.
130 */
131static int
132mptsas_slave_alloc(struct scsi_device *device)
133{
134 struct Scsi_Host *host = device->host;
135 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
136 struct sas_rphy *rphy;
137 struct mptsas_portinfo *p;
138 VirtDevice *vdev;
139 uint target = device->id;
140 int i;
141
142 if ((vdev = hd->Targets[target]) != NULL)
143 goto out;
144
145 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
146 if (!vdev) {
147 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
148 hd->ioc->name, sizeof(VirtDevice));
149 return -ENOMEM;
150 }
151
152 memset(vdev, 0, sizeof(VirtDevice));
153 vdev->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
154 vdev->ioc_id = hd->ioc->id;
155
156 rphy = dev_to_rphy(device->sdev_target->dev.parent);
157 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
158 for (i = 0; i < p->num_phys; i++) {
159 if (p->phy_info[i].attached.sas_address ==
160 rphy->identify.sas_address) {
161 vdev->target_id =
162 p->phy_info[i].attached.target;
163 vdev->bus_id = p->phy_info[i].attached.bus;
164 hd->Targets[device->id] = vdev;
165 goto out;
166 }
167 }
168 }
169
170 printk("No matching SAS device found!!\n");
171 kfree(vdev);
172 return -ENODEV;
173
174 out:
175 vdev->num_luns++;
176 device->hostdata = vdev;
177 return 0;
178}
179
180static struct scsi_host_template mptsas_driver_template = {
181 .proc_name = "mptsas",
182 .proc_info = mptscsih_proc_info,
183 .name = "MPT SPI Host",
184 .info = mptscsih_info,
185 .queuecommand = mptscsih_qcmd,
186 .slave_alloc = mptsas_slave_alloc,
187 .slave_configure = mptscsih_slave_configure,
188 .slave_destroy = mptscsih_slave_destroy,
189 .change_queue_depth = mptscsih_change_queue_depth,
190 .eh_abort_handler = mptscsih_abort,
191 .eh_device_reset_handler = mptscsih_dev_reset,
192 .eh_bus_reset_handler = mptscsih_bus_reset,
193 .eh_host_reset_handler = mptscsih_host_reset,
194 .bios_param = mptscsih_bios_param,
195 .can_queue = MPT_FC_CAN_QUEUE,
196 .this_id = -1,
197 .sg_tablesize = MPT_SCSI_SG_DEPTH,
198 .max_sectors = 8192,
199 .cmd_per_lun = 7,
200 .use_clustering = ENABLE_CLUSTERING,
201};
202
203static struct sas_function_template mptsas_transport_functions = {
204};
205
206static struct scsi_transport_template *mptsas_transport_template;
207
208#ifdef SASDEBUG
209static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
210{
211 printk("---- IO UNIT PAGE 0 ------------\n");
212 printk("Handle=0x%X\n",
213 le16_to_cpu(phy_data->AttachedDeviceHandle));
214 printk("Controller Handle=0x%X\n",
215 le16_to_cpu(phy_data->ControllerDevHandle));
216 printk("Port=0x%X\n", phy_data->Port);
217 printk("Port Flags=0x%X\n", phy_data->PortFlags);
218 printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
219 printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
220 printk("Controller PHY Device Info=0x%X\n",
221 le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
222 printk("DiscoveryStatus=0x%X\n",
223 le32_to_cpu(phy_data->DiscoveryStatus));
224 printk("\n");
225}
226
227static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
228{
229 __le64 sas_address;
230
231 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
232
233 printk("---- SAS PHY PAGE 0 ------------\n");
234 printk("Attached Device Handle=0x%X\n",
235 le16_to_cpu(pg0->AttachedDevHandle));
236 printk("SAS Address=0x%llX\n",
237 (unsigned long long)le64_to_cpu(sas_address));
238 printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
239 printk("Attached Device Info=0x%X\n",
240 le32_to_cpu(pg0->AttachedDeviceInfo));
241 printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
242 printk("Change Count=0x%X\n", pg0->ChangeCount);
243 printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
244 printk("\n");
245}
246
247static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
248{
249 __le64 sas_address;
250
251 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
252
253 printk("---- SAS DEVICE PAGE 0 ---------\n");
254 printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
255 printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
256 printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
257 printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
258 printk("Target ID=0x%X\n", pg0->TargetID);
259 printk("Bus=0x%X\n", pg0->Bus);
260 printk("PhyNum=0x%X\n", pg0->PhyNum);
261 printk("AccessStatus=0x%X\n", le16_to_cpu(pg0->AccessStatus));
262 printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
263 printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
264 printk("Physical Port=0x%X\n", pg0->PhysicalPort);
265 printk("\n");
266}
267
268static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
269{
270 printk("---- SAS EXPANDER PAGE 1 ------------\n");
271
272 printk("Physical Port=0x%X\n", pg1->PhysicalPort);
273 printk("PHY Identifier=0x%X\n", pg1->Phy);
274 printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
275 printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
276 printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
277 printk("Owner Device Handle=0x%X\n",
278 le16_to_cpu(pg1->OwnerDevHandle));
279 printk("Attached Device Handle=0x%X\n",
280 le16_to_cpu(pg1->AttachedDevHandle));
281}
282#else
283#define mptsas_print_phy_data(phy_data) do { } while (0)
284#define mptsas_print_phy_pg0(pg0) do { } while (0)
285#define mptsas_print_device_pg0(pg0) do { } while (0)
286#define mptsas_print_expander_pg1(pg1) do { } while (0)
287#endif
288
289static int
290mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
291{
292 ConfigExtendedPageHeader_t hdr;
293 CONFIGPARMS cfg;
294 SasIOUnitPage0_t *buffer;
295 dma_addr_t dma_handle;
296 int error, i;
297
298 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
299 hdr.ExtPageLength = 0;
300 hdr.PageNumber = 0;
301 hdr.Reserved1 = 0;
302 hdr.Reserved2 = 0;
303 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
304 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
305
306 cfg.cfghdr.ehdr = &hdr;
307 cfg.physAddr = -1;
308 cfg.pageAddr = 0;
309 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
310 cfg.dir = 0; /* read */
311 cfg.timeout = 10;
312
313 error = mpt_config(ioc, &cfg);
314 if (error)
315 goto out;
316 if (!hdr.ExtPageLength) {
317 error = -ENXIO;
318 goto out;
319 }
320
321 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
322 &dma_handle);
323 if (!buffer) {
324 error = -ENOMEM;
325 goto out;
326 }
327
328 cfg.physAddr = dma_handle;
329 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
330
331 error = mpt_config(ioc, &cfg);
332 if (error)
333 goto out_free_consistent;
334
335 port_info->num_phys = buffer->NumPhys;
336 port_info->phy_info = kcalloc(port_info->num_phys,
337 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
338 if (!port_info->phy_info) {
339 error = -ENOMEM;
340 goto out_free_consistent;
341 }
342
343 for (i = 0; i < port_info->num_phys; i++) {
344 mptsas_print_phy_data(&buffer->PhyData[i]);
345 port_info->phy_info[i].phy_id = i;
346 port_info->phy_info[i].port_id =
347 buffer->PhyData[i].Port;
348 port_info->phy_info[i].negotiated_link_rate =
349 buffer->PhyData[i].NegotiatedLinkRate;
350 }
351
352 out_free_consistent:
353 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
354 buffer, dma_handle);
355 out:
356 return error;
357}
358
359static int
360mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
361 u32 form, u32 form_specific)
362{
363 ConfigExtendedPageHeader_t hdr;
364 CONFIGPARMS cfg;
365 SasPhyPage0_t *buffer;
366 dma_addr_t dma_handle;
367 int error;
368
369 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
370 hdr.ExtPageLength = 0;
371 hdr.PageNumber = 0;
372 hdr.Reserved1 = 0;
373 hdr.Reserved2 = 0;
374 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
375 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
376
377 cfg.cfghdr.ehdr = &hdr;
378 cfg.dir = 0; /* read */
379 cfg.timeout = 10;
380
381 /* Get Phy Pg 0 for each Phy. */
382 cfg.physAddr = -1;
383 cfg.pageAddr = form + form_specific;
384 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
385
386 error = mpt_config(ioc, &cfg);
387 if (error)
388 goto out;
389
390 if (!hdr.ExtPageLength) {
391 error = -ENXIO;
392 goto out;
393 }
394
395 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
396 &dma_handle);
397 if (!buffer) {
398 error = -ENOMEM;
399 goto out;
400 }
401
402 cfg.physAddr = dma_handle;
403 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
404
405 error = mpt_config(ioc, &cfg);
406 if (error)
407 goto out_free_consistent;
408
409 mptsas_print_phy_pg0(buffer);
410
411 phy_info->hw_link_rate = buffer->HwLinkRate;
412 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
413 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
414 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
415
416 out_free_consistent:
417 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
418 buffer, dma_handle);
419 out:
420 return error;
421}
422
423static int
424mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
425 u32 form, u32 form_specific)
426{
427 ConfigExtendedPageHeader_t hdr;
428 CONFIGPARMS cfg;
429 SasDevicePage0_t *buffer;
430 dma_addr_t dma_handle;
431 __le64 sas_address;
432 int error;
433
434 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
435 hdr.ExtPageLength = 0;
436 hdr.PageNumber = 0;
437 hdr.Reserved1 = 0;
438 hdr.Reserved2 = 0;
439 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
440 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
441
442 cfg.cfghdr.ehdr = &hdr;
443 cfg.pageAddr = form + form_specific;
444 cfg.physAddr = -1;
445 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
446 cfg.dir = 0; /* read */
447 cfg.timeout = 10;
448
449 error = mpt_config(ioc, &cfg);
450 if (error)
451 goto out;
452 if (!hdr.ExtPageLength) {
453 error = -ENXIO;
454 goto out;
455 }
456
457 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
458 &dma_handle);
459 if (!buffer) {
460 error = -ENOMEM;
461 goto out;
462 }
463
464 cfg.physAddr = dma_handle;
465 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
466
467 error = mpt_config(ioc, &cfg);
468 if (error)
469 goto out_free_consistent;
470
471 mptsas_print_device_pg0(buffer);
472
473 device_info->handle = le16_to_cpu(buffer->DevHandle);
474 device_info->phy_id = buffer->PhyNum;
475 device_info->port_id = buffer->PhysicalPort;
476 device_info->target = buffer->TargetID;
477 device_info->bus = buffer->Bus;
478 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
479 device_info->sas_address = le64_to_cpu(sas_address);
480 device_info->device_info =
481 le32_to_cpu(buffer->DeviceInfo);
482
483 out_free_consistent:
484 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
485 buffer, dma_handle);
486 out:
487 return error;
488}
489
490static int
491mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
492 u32 form, u32 form_specific)
493{
494 ConfigExtendedPageHeader_t hdr;
495 CONFIGPARMS cfg;
496 SasExpanderPage0_t *buffer;
497 dma_addr_t dma_handle;
498 int error;
499
500 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
501 hdr.ExtPageLength = 0;
502 hdr.PageNumber = 0;
503 hdr.Reserved1 = 0;
504 hdr.Reserved2 = 0;
505 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
506 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
507
508 cfg.cfghdr.ehdr = &hdr;
509 cfg.physAddr = -1;
510 cfg.pageAddr = form + form_specific;
511 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
512 cfg.dir = 0; /* read */
513 cfg.timeout = 10;
514
515 error = mpt_config(ioc, &cfg);
516 if (error)
517 goto out;
518
519 if (!hdr.ExtPageLength) {
520 error = -ENXIO;
521 goto out;
522 }
523
524 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
525 &dma_handle);
526 if (!buffer) {
527 error = -ENOMEM;
528 goto out;
529 }
530
531 cfg.physAddr = dma_handle;
532 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
533
534 error = mpt_config(ioc, &cfg);
535 if (error)
536 goto out_free_consistent;
537
538 /* save config data */
539 port_info->num_phys = buffer->NumPhys;
540 port_info->handle = le16_to_cpu(buffer->DevHandle);
541 port_info->phy_info = kcalloc(port_info->num_phys,
542 sizeof(struct mptsas_phyinfo),GFP_KERNEL);
543 if (!port_info->phy_info) {
544 error = -ENOMEM;
545 goto out_free_consistent;
546 }
547
548 out_free_consistent:
549 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
550 buffer, dma_handle);
551 out:
552 return error;
553}
554
555static int
556mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
557 u32 form, u32 form_specific)
558{
559 ConfigExtendedPageHeader_t hdr;
560 CONFIGPARMS cfg;
561 SasExpanderPage1_t *buffer;
562 dma_addr_t dma_handle;
563 int error;
564
565 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
566 hdr.ExtPageLength = 0;
567 hdr.PageNumber = 1;
568 hdr.Reserved1 = 0;
569 hdr.Reserved2 = 0;
570 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
571 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
572
573 cfg.cfghdr.ehdr = &hdr;
574 cfg.physAddr = -1;
575 cfg.pageAddr = form + form_specific;
576 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
577 cfg.dir = 0; /* read */
578 cfg.timeout = 10;
579
580 error = mpt_config(ioc, &cfg);
581 if (error)
582 goto out;
583
584 if (!hdr.ExtPageLength) {
585 error = -ENXIO;
586 goto out;
587 }
588
589 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
590 &dma_handle);
591 if (!buffer) {
592 error = -ENOMEM;
593 goto out;
594 }
595
596 cfg.physAddr = dma_handle;
597 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
598
599 error = mpt_config(ioc, &cfg);
600 if (error)
601 goto out_free_consistent;
602
603
604 mptsas_print_expander_pg1(buffer);
605
606 /* save config data */
607 phy_info->phy_id = buffer->Phy;
608 phy_info->port_id = buffer->PhysicalPort;
609 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
610 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
611 phy_info->hw_link_rate = buffer->HwLinkRate;
612 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
613 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
614
615
616 out_free_consistent:
617 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
618 buffer, dma_handle);
619 out:
620 return error;
621}
622
623static void
624mptsas_parse_device_info(struct sas_identify *identify,
625 struct mptsas_devinfo *device_info)
626{
627 u16 protocols;
628
629 identify->sas_address = device_info->sas_address;
630 identify->phy_identifier = device_info->phy_id;
631
632 /*
633 * Fill in Phy Initiator Port Protocol.
634 * Bits 6:3, more than one bit can be set, fall through cases.
635 */
636 protocols = device_info->device_info & 0x78;
637 identify->initiator_port_protocols = 0;
638 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
639 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
640 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
641 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
642 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
643 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
644 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
645 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
646
647 /*
648 * Fill in Phy Target Port Protocol.
649 * Bits 10:7, more than one bit can be set, fall through cases.
650 */
651 protocols = device_info->device_info & 0x780;
652 identify->target_port_protocols = 0;
653 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
654 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
655 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
656 identify->target_port_protocols |= SAS_PROTOCOL_STP;
657 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
658 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
659 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
660 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
661
662 /*
663 * Fill in Attached device type.
664 */
665 switch (device_info->device_info &
666 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
667 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
668 identify->device_type = SAS_PHY_UNUSED;
669 break;
670 case MPI_SAS_DEVICE_INFO_END_DEVICE:
671 identify->device_type = SAS_END_DEVICE;
672 break;
673 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
674 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
675 break;
676 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
677 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
678 break;
679 }
680}
681
682static int mptsas_probe_one_phy(struct device *dev,
683 struct mptsas_phyinfo *phy_info, int index)
684{
685 struct sas_phy *port;
686 int error;
687
688 port = sas_phy_alloc(dev, index);
689 if (!port)
690 return -ENOMEM;
691
692 port->port_identifier = phy_info->port_id;
693 mptsas_parse_device_info(&port->identify, &phy_info->identify);
694
695 /*
696 * Set Negotiated link rate.
697 */
698 switch (phy_info->negotiated_link_rate) {
699 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
700 port->negotiated_linkrate = SAS_PHY_DISABLED;
701 break;
702 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
703 port->negotiated_linkrate = SAS_LINK_RATE_FAILED;
704 break;
705 case MPI_SAS_IOUNIT0_RATE_1_5:
706 port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
707 break;
708 case MPI_SAS_IOUNIT0_RATE_3_0:
709 port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
710 break;
711 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
712 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
713 default:
714 port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
715 break;
716 }
717
718 /*
719 * Set Max hardware link rate.
720 */
721 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
722 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
723 port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
724 break;
725 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
726 port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
727 break;
728 default:
729 break;
730 }
731
732 /*
733 * Set Max programmed link rate.
734 */
735 switch (phy_info->programmed_link_rate &
736 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
737 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
738 port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
739 break;
740 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
741 port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
742 break;
743 default:
744 break;
745 }
746
747 /*
748 * Set Min hardware link rate.
749 */
750 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
751 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
752 port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
753 break;
754 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
755 port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
756 break;
757 default:
758 break;
759 }
760
761 /*
762 * Set Min programmed link rate.
763 */
764 switch (phy_info->programmed_link_rate &
765 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
766 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
767 port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
768 break;
769 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
770 port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
771 break;
772 default:
773 break;
774 }
775
776 error = sas_phy_add(port);
777 if (error) {
778 sas_phy_free(port);
779 return error;
780 }
781
782 if (phy_info->attached.handle) {
783 struct sas_rphy *rphy;
784
785 rphy = sas_rphy_alloc(port);
786 if (!rphy)
787 return 0; /* non-fatal: an rphy can be added later */
788
789 mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
790 error = sas_rphy_add(rphy);
791 if (error) {
792 sas_rphy_free(rphy);
793 return error;
794 }
795
796 phy_info->rphy = rphy;
797 }
798
799 return 0;
800}
801
802static int
803mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index)
804{
805 struct mptsas_portinfo *port_info;
806 u32 handle = 0xFFFF;
807 int error = -ENOMEM, i;
808
809 port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
810 if (!port_info)
811 goto out;
812 memset(port_info, 0, sizeof(*port_info));
813
814 error = mptsas_sas_io_unit_pg0(ioc, port_info);
815 if (error)
816 goto out_free_port_info;
817
818 list_add_tail(&port_info->list, &ioc->sas_topology);
819
820 for (i = 0; i < port_info->num_phys; i++) {
821 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
822 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
823 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
824
825 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
826 (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
827 MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
828 handle = port_info->phy_info[i].identify.handle;
829
830 if (port_info->phy_info[i].attached.handle) {
831 mptsas_sas_device_pg0(ioc,
832 &port_info->phy_info[i].attached,
833 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
834 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
835 port_info->phy_info[i].attached.handle);
836 }
837
838 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
839 &port_info->phy_info[i], *index);
840 (*index)++;
841 }
842
843 return 0;
844
845 out_free_port_info:
846 kfree(port_info);
847 out:
848 return error;
849}
850
851static int
852mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
853{
854 struct mptsas_portinfo *port_info, *p;
855 int error = -ENOMEM, i, j;
856
857 port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
858 if (!port_info)
859 goto out;
860 memset(port_info, 0, sizeof(*port_info));
861
862 error = mptsas_sas_expander_pg0(ioc, port_info,
863 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
864 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
865 if (error)
866 goto out_free_port_info;
867
868 *handle = port_info->handle;
869
870 list_add_tail(&port_info->list, &ioc->sas_topology);
871 for (i = 0; i < port_info->num_phys; i++) {
872 struct device *parent;
873
874 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
875 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
876 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
877
878 if (port_info->phy_info[i].identify.handle) {
879 mptsas_sas_device_pg0(ioc,
880 &port_info->phy_info[i].identify,
881 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
882 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
883 port_info->phy_info[i].identify.handle);
884 }
885
886 if (port_info->phy_info[i].attached.handle) {
887 mptsas_sas_device_pg0(ioc,
888 &port_info->phy_info[i].attached,
889 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
890 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
891 port_info->phy_info[i].attached.handle);
892 }
893
894 /*
895 * If we find a parent port handle this expander is
896 * attached to another expander, else it hangs of the
897 * HBA phys.
898 */
899 parent = &ioc->sh->shost_gendev;
900 list_for_each_entry(p, &ioc->sas_topology, list) {
901 for (j = 0; j < p->num_phys; j++) {
902 if (port_info->phy_info[i].identify.handle ==
903 p->phy_info[j].attached.handle)
904 parent = &p->phy_info[j].rphy->dev;
905 }
906 }
907
908 mptsas_probe_one_phy(parent, &port_info->phy_info[i], *index);
909 (*index)++;
910 }
911
912 return 0;
913
914 out_free_port_info:
915 kfree(port_info);
916 out:
917 return error;
918}
919
920static void
921mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
922{
923 u32 handle = 0xFFFF;
924 int index = 0;
925
926 mptsas_probe_hba_phys(ioc, &index);
927 while (!mptsas_probe_expander_phys(ioc, &handle, &index))
928 ;
929}
930
931static int
932mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
933{
934 struct Scsi_Host *sh;
935 MPT_SCSI_HOST *hd;
936 MPT_ADAPTER *ioc;
937 unsigned long flags;
938 int sz, ii;
939 int numSGE = 0;
940 int scale;
941 int ioc_cap;
942 u8 *mem;
943 int error=0;
944 int r;
945
946 r = mpt_attach(pdev,id);
947 if (r)
948 return r;
949
950 ioc = pci_get_drvdata(pdev);
951 ioc->DoneCtx = mptsasDoneCtx;
952 ioc->TaskCtx = mptsasTaskCtx;
953 ioc->InternalCtx = mptsasInternalCtx;
954
955 /* Added sanity check on readiness of the MPT adapter.
956 */
957 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
958 printk(MYIOC_s_WARN_FMT
959 "Skipping because it's not operational!\n",
960 ioc->name);
961 return -ENODEV;
962 }
963
964 if (!ioc->active) {
965 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
966 ioc->name);
967 return -ENODEV;
968 }
969
970 /* Sanity check - ensure at least 1 port is INITIATOR capable
971 */
972 ioc_cap = 0;
973 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
974 if (ioc->pfacts[ii].ProtocolFlags &
975 MPI_PORTFACTS_PROTOCOL_INITIATOR)
976 ioc_cap++;
977 }
978
979 if (!ioc_cap) {
980 printk(MYIOC_s_WARN_FMT
981 "Skipping ioc=%p because SCSI Initiator mode "
982 "is NOT enabled!\n", ioc->name, ioc);
983 return -ENODEV;
984 }
985
986 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
987 if (!sh) {
988 printk(MYIOC_s_WARN_FMT
989 "Unable to register controller with SCSI subsystem\n",
990 ioc->name);
991 return -1;
992 }
993
994 spin_lock_irqsave(&ioc->FreeQlock, flags);
995
996 /* Attach the SCSI Host to the IOC structure
997 */
998 ioc->sh = sh;
999
1000 sh->io_port = 0;
1001 sh->n_io_port = 0;
1002 sh->irq = 0;
1003
1004 /* set 16 byte cdb's */
1005 sh->max_cmd_len = 16;
1006
1007 sh->max_id = ioc->pfacts->MaxDevices + 1;
1008
1009 sh->transportt = mptsas_transport_template;
1010
1011 sh->max_lun = MPT_LAST_LUN + 1;
1012 sh->max_channel = 0;
1013 sh->this_id = ioc->pfacts[0].PortSCSIID;
1014
1015 /* Required entry.
1016 */
1017 sh->unique_id = ioc->id;
1018
1019 INIT_LIST_HEAD(&ioc->sas_topology);
1020
1021 /* Verify that we won't exceed the maximum
1022 * number of chain buffers
1023 * We can optimize: ZZ = req_sz/sizeof(SGE)
1024 * For 32bit SGE's:
1025 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
1026 * + (req_sz - 64)/sizeof(SGE)
1027 * A slightly different algorithm is required for
1028 * 64bit SGEs.
1029 */
1030 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
1031 if (sizeof(dma_addr_t) == sizeof(u64)) {
1032 numSGE = (scale - 1) *
1033 (ioc->facts.MaxChainDepth-1) + scale +
1034 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
1035 sizeof(u32));
1036 } else {
1037 numSGE = 1 + (scale - 1) *
1038 (ioc->facts.MaxChainDepth-1) + scale +
1039 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
1040 sizeof(u32));
1041 }
1042
1043 if (numSGE < sh->sg_tablesize) {
1044 /* Reset this value */
1045 dprintk((MYIOC_s_INFO_FMT
1046 "Resetting sg_tablesize to %d from %d\n",
1047 ioc->name, numSGE, sh->sg_tablesize));
1048 sh->sg_tablesize = numSGE;
1049 }
1050
1051 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1052
1053 hd = (MPT_SCSI_HOST *) sh->hostdata;
1054 hd->ioc = ioc;
1055
1056 /* SCSI needs scsi_cmnd lookup table!
1057 * (with size equal to req_depth*PtrSz!)
1058 */
1059 sz = ioc->req_depth * sizeof(void *);
1060 mem = kmalloc(sz, GFP_ATOMIC);
1061 if (mem == NULL) {
1062 error = -ENOMEM;
1063 goto mptsas_probe_failed;
1064 }
1065
1066 memset(mem, 0, sz);
1067 hd->ScsiLookup = (struct scsi_cmnd **) mem;
1068
1069 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
1070 ioc->name, hd->ScsiLookup, sz));
1071
1072 /* Allocate memory for the device structures.
1073 * A non-Null pointer at an offset
1074 * indicates a device exists.
1075 * max_id = 1 + maximum id (hosts.h)
1076 */
1077 sz = sh->max_id * sizeof(void *);
1078 mem = kmalloc(sz, GFP_ATOMIC);
1079 if (mem == NULL) {
1080 error = -ENOMEM;
1081 goto mptsas_probe_failed;
1082 }
1083
1084 memset(mem, 0, sz);
1085 hd->Targets = (VirtDevice **) mem;
1086
1087 dprintk((KERN_INFO
1088 " Targets @ %p, sz=%d\n", hd->Targets, sz));
1089
1090 /* Clear the TM flags
1091 */
1092 hd->tmPending = 0;
1093 hd->tmState = TM_STATE_NONE;
1094 hd->resetPending = 0;
1095 hd->abortSCpnt = NULL;
1096
1097 /* Clear the pointer used to store
1098 * single-threaded commands, i.e., those
1099 * issued during a bus scan, dv and
1100 * configuration pages.
1101 */
1102 hd->cmdPtr = NULL;
1103
1104 /* Initialize this SCSI Hosts' timers
1105 * To use, set the timer expires field
1106 * and add_timer
1107 */
1108 init_timer(&hd->timer);
1109 hd->timer.data = (unsigned long) hd;
1110 hd->timer.function = mptscsih_timer_expired;
1111
1112 hd->mpt_pq_filter = mpt_pq_filter;
1113 ioc->sas_data.ptClear = mpt_pt_clear;
1114
1115 if (ioc->sas_data.ptClear==1) {
1116 mptbase_sas_persist_operation(
1117 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
1118 }
1119
1120 ddvprintk((MYIOC_s_INFO_FMT
1121 "mpt_pq_filter %x mpt_pq_filter %x\n",
1122 ioc->name,
1123 mpt_pq_filter,
1124 mpt_pq_filter));
1125
1126 init_waitqueue_head(&hd->scandv_waitq);
1127 hd->scandv_wait_done = 0;
1128 hd->last_queue_full = 0;
1129
1130 error = scsi_add_host(sh, &ioc->pcidev->dev);
1131 if (error) {
1132 dprintk((KERN_ERR MYNAM
1133 "scsi_add_host failed\n"));
1134 goto mptsas_probe_failed;
1135 }
1136
1137 mptsas_scan_sas_topology(ioc);
1138
1139 return 0;
1140
1141mptsas_probe_failed:
1142
1143 mptscsih_remove(pdev);
1144 return error;
1145}
1146
1147static void __devexit mptsas_remove(struct pci_dev *pdev)
1148{
1149 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1150 struct mptsas_portinfo *p, *n;
1151
1152 sas_remove_host(ioc->sh);
1153
1154 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
1155 list_del(&p->list);
1156 kfree(p);
1157 }
1158
1159 mptscsih_remove(pdev);
1160}
1161
1162static struct pci_device_id mptsas_pci_table[] = {
1163 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
1164 PCI_ANY_ID, PCI_ANY_ID },
1165 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
1166 PCI_ANY_ID, PCI_ANY_ID },
1167 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
1168 PCI_ANY_ID, PCI_ANY_ID },
1169 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
1170 PCI_ANY_ID, PCI_ANY_ID },
1171 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
1172 PCI_ANY_ID, PCI_ANY_ID },
1173 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
1174 PCI_ANY_ID, PCI_ANY_ID },
1175 {0} /* Terminating entry */
1176};
1177MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
1178
1179
1180static struct pci_driver mptsas_driver = {
1181 .name = "mptsas",
1182 .id_table = mptsas_pci_table,
1183 .probe = mptsas_probe,
1184 .remove = __devexit_p(mptsas_remove),
1185 .shutdown = mptscsih_shutdown,
1186#ifdef CONFIG_PM
1187 .suspend = mptscsih_suspend,
1188 .resume = mptscsih_resume,
1189#endif
1190};
1191
1192static int __init
1193mptsas_init(void)
1194{
1195 show_mptmod_ver(my_NAME, my_VERSION);
1196
1197 mptsas_transport_template =
1198 sas_attach_transport(&mptsas_transport_functions);
1199 if (!mptsas_transport_template)
1200 return -ENODEV;
1201
1202 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
1203 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
1204 mptsasInternalCtx =
1205 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
1206
1207 if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
1208 devtprintk((KERN_INFO MYNAM
1209 ": Registered for IOC event notifications\n"));
1210 }
1211
1212 if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
1213 dprintk((KERN_INFO MYNAM
1214 ": Registered for IOC reset notifications\n"));
1215 }
1216
1217 return pci_register_driver(&mptsas_driver);
1218}
1219
1220static void __exit
1221mptsas_exit(void)
1222{
1223 pci_unregister_driver(&mptsas_driver);
1224 sas_release_transport(mptsas_transport_template);
1225
1226 mpt_reset_deregister(mptsasDoneCtx);
1227 mpt_event_deregister(mptsasDoneCtx);
1228
1229 mpt_deregister(mptsasInternalCtx);
1230 mpt_deregister(mptsasTaskCtx);
1231 mpt_deregister(mptsasDoneCtx);
1232}
1233
1234module_init(mptsas_init);
1235module_exit(mptsas_exit);