[SCSI] mptfusion: move fc event/reset handling to mptfc
[pandora-kernel.git] / drivers / message / fusion / mptfc.c
1 /*
2  *  linux/drivers/message/fusion/mptfc.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  *
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 #include "linux_compat.h"       /* linux-2.6 tweaks */
47 #include <linux/module.h>
48 #include <linux/kernel.h>
49 #include <linux/init.h>
50 #include <linux/errno.h>
51 #include <linux/kdev_t.h>
52 #include <linux/blkdev.h>
53 #include <linux/delay.h>        /* for mdelay */
54 #include <linux/interrupt.h>    /* needed for in_interrupt() proto */
55 #include <linux/reboot.h>       /* notifier code */
56 #include <linux/sched.h>
57 #include <linux/workqueue.h>
58 #include <linux/sort.h>
59
60 #include <scsi/scsi.h>
61 #include <scsi/scsi_cmnd.h>
62 #include <scsi/scsi_device.h>
63 #include <scsi/scsi_host.h>
64 #include <scsi/scsi_tcq.h>
65 #include <scsi/scsi_transport_fc.h>
66
67 #include "mptbase.h"
68 #include "mptscsih.h"
69
70 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71 #define my_NAME         "Fusion MPT FC Host driver"
72 #define my_VERSION      MPT_LINUX_VERSION_COMMON
73 #define MYNAM           "mptfc"
74
75 MODULE_AUTHOR(MODULEAUTHOR);
76 MODULE_DESCRIPTION(my_NAME);
77 MODULE_LICENSE("GPL");
78
79 /* Command line args */
80 static int mpt_pq_filter = 0;
81 module_param(mpt_pq_filter, int, 0);
82 MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
83
84 #define MPTFC_DEV_LOSS_TMO (60)
85 static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;     /* reasonable default */
86 module_param(mptfc_dev_loss_tmo, int, 0);
87 MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
88                                      " transport to wait for an rport to "
89                                      " return following a device loss event."
90                                      "  Default=60.");
91
92 static int      mptfcDoneCtx = -1;
93 static int      mptfcTaskCtx = -1;
94 static int      mptfcInternalCtx = -1; /* Used only for internal commands */
95
96 static int mptfc_target_alloc(struct scsi_target *starget);
97 static int mptfc_slave_alloc(struct scsi_device *sdev);
98 static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
99                       void (*done)(struct scsi_cmnd *));
100 static void mptfc_target_destroy(struct scsi_target *starget);
101 static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
102 static void __devexit mptfc_remove(struct pci_dev *pdev);
103
104 static struct scsi_host_template mptfc_driver_template = {
105         .module                         = THIS_MODULE,
106         .proc_name                      = "mptfc",
107         .proc_info                      = mptscsih_proc_info,
108         .name                           = "MPT FC Host",
109         .info                           = mptscsih_info,
110         .queuecommand                   = mptfc_qcmd,
111         .target_alloc                   = mptfc_target_alloc,
112         .slave_alloc                    = mptfc_slave_alloc,
113         .slave_configure                = mptscsih_slave_configure,
114         .target_destroy                 = mptfc_target_destroy,
115         .slave_destroy                  = mptscsih_slave_destroy,
116         .change_queue_depth             = mptscsih_change_queue_depth,
117         .eh_abort_handler               = mptscsih_abort,
118         .eh_device_reset_handler        = mptscsih_dev_reset,
119         .eh_bus_reset_handler           = mptscsih_bus_reset,
120         .eh_host_reset_handler          = mptscsih_host_reset,
121         .bios_param                     = mptscsih_bios_param,
122         .can_queue                      = MPT_FC_CAN_QUEUE,
123         .this_id                        = -1,
124         .sg_tablesize                   = MPT_SCSI_SG_DEPTH,
125         .max_sectors                    = 8192,
126         .cmd_per_lun                    = 7,
127         .use_clustering                 = ENABLE_CLUSTERING,
128 };
129
130 /****************************************************************************
131  * Supported hardware
132  */
133
134 static struct pci_device_id mptfc_pci_table[] = {
135         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909,
136                 PCI_ANY_ID, PCI_ANY_ID },
137         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919,
138                 PCI_ANY_ID, PCI_ANY_ID },
139         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929,
140                 PCI_ANY_ID, PCI_ANY_ID },
141         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X,
142                 PCI_ANY_ID, PCI_ANY_ID },
143         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X,
144                 PCI_ANY_ID, PCI_ANY_ID },
145         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X,
146                 PCI_ANY_ID, PCI_ANY_ID },
147         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
148                 PCI_ANY_ID, PCI_ANY_ID },
149         { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
150                 PCI_ANY_ID, PCI_ANY_ID },
151         {0}     /* Terminating entry */
152 };
153 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
154
155 static struct scsi_transport_template *mptfc_transport_template = NULL;
156
157 static struct fc_function_template mptfc_transport_functions = {
158         .dd_fcrport_size = 8,
159         .show_host_node_name = 1,
160         .show_host_port_name = 1,
161         .show_host_supported_classes = 1,
162         .show_host_port_id = 1,
163         .show_rport_supported_classes = 1,
164         .show_starget_node_name = 1,
165         .show_starget_port_name = 1,
166         .show_starget_port_id = 1,
167         .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
168         .show_rport_dev_loss_tmo = 1,
169
170 };
171
172 /* FIXME! values controlling firmware RESCAN event
173  * need to be set low to allow dev_loss_tmo to
174  * work as expected.  Currently, firmware doesn't
175  * notify driver of RESCAN event until some number
176  * of seconds elapse.  This value can be set via
177  * lsiutil.
178  */
179 static void
180 mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
181 {
182         if (timeout > 0)
183                 rport->dev_loss_tmo = timeout;
184         else
185                 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
186 }
187
188 static int
189 mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
190 {
191         FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
192         FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
193
194         if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
195                 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
196                         return 0;
197                 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
198                         return -1;
199                 return 1;
200         }
201         if ((*aa)->CurrentBus < (*bb)->CurrentBus)
202                 return -1;
203         return 1;
204 }
205
206 static int
207 mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
208         void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
209 {
210         ConfigPageHeader_t       hdr;
211         CONFIGPARMS              cfg;
212         FCDevicePage0_t         *ppage0_alloc, *fc;
213         dma_addr_t               page0_dma;
214         int                      data_sz;
215         int                      ii;
216
217         FCDevicePage0_t         *p0_array=NULL, *p_p0;
218         FCDevicePage0_t         **pp0_array=NULL, **p_pp0;
219
220         int                      rc = -ENOMEM;
221         U32                      port_id = 0xffffff;
222         int                      num_targ = 0;
223         int                      max_bus = ioc->facts.MaxBuses;
224         int                      max_targ = ioc->facts.MaxDevices;
225
226         if (max_bus == 0 || max_targ == 0)
227                 goto out;
228
229         data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
230         p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);
231         if (!p0_array)
232                 goto out;
233
234         data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
235         p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
236         if (!pp0_array)
237                 goto out;
238
239         do {
240                 /* Get FC Device Page 0 header */
241                 hdr.PageVersion = 0;
242                 hdr.PageLength = 0;
243                 hdr.PageNumber = 0;
244                 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
245                 cfg.cfghdr.hdr = &hdr;
246                 cfg.physAddr = -1;
247                 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
248                 cfg.dir = 0;
249                 cfg.pageAddr = port_id;
250                 cfg.timeout = 0;
251
252                 if ((rc = mpt_config(ioc, &cfg)) != 0)
253                         break;
254
255                 if (hdr.PageLength <= 0)
256                         break;
257
258                 data_sz = hdr.PageLength * 4;
259                 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
260                                                         &page0_dma);
261                 rc = -ENOMEM;
262                 if (!ppage0_alloc)
263                         break;
264
265                 cfg.physAddr = page0_dma;
266                 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
267
268                 if ((rc = mpt_config(ioc, &cfg)) == 0) {
269                         ppage0_alloc->PortIdentifier =
270                                 le32_to_cpu(ppage0_alloc->PortIdentifier);
271
272                         ppage0_alloc->WWNN.Low =
273                                 le32_to_cpu(ppage0_alloc->WWNN.Low);
274
275                         ppage0_alloc->WWNN.High =
276                                 le32_to_cpu(ppage0_alloc->WWNN.High);
277
278                         ppage0_alloc->WWPN.Low =
279                                 le32_to_cpu(ppage0_alloc->WWPN.Low);
280
281                         ppage0_alloc->WWPN.High =
282                                 le32_to_cpu(ppage0_alloc->WWPN.High);
283
284                         ppage0_alloc->BBCredit =
285                                 le16_to_cpu(ppage0_alloc->BBCredit);
286
287                         ppage0_alloc->MaxRxFrameSize =
288                                 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
289
290                         port_id = ppage0_alloc->PortIdentifier;
291                         num_targ++;
292                         *p_p0 = *ppage0_alloc;  /* save data */
293                         *p_pp0++ = p_p0++;      /* save addr */
294                 }
295                 pci_free_consistent(ioc->pcidev, data_sz,
296                                         (u8 *) ppage0_alloc, page0_dma);
297                 if (rc != 0)
298                         break;
299
300         } while (port_id <= 0xff0000);
301
302         if (num_targ) {
303                 /* sort array */
304                 if (num_targ > 1)
305                         sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
306                                 mptfc_FcDevPage0_cmp_func, NULL);
307                 /* call caller's func for each targ */
308                 for (ii = 0; ii < num_targ;  ii++) {
309                         fc = *(pp0_array+ii);
310                         func(ioc, ioc_port, fc);
311                 }
312         }
313
314  out:
315         if (pp0_array)
316                 kfree(pp0_array);
317         if (p0_array)
318                 kfree(p0_array);
319         return rc;
320 }
321
322 static int
323 mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
324 {
325         /* not currently usable */
326         if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
327                           MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
328                 return -1;
329
330         if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
331                 return -1;
332
333         if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
334                 return -1;
335
336         /*
337          * board data structure already normalized to platform endianness
338          * shifted to avoid unaligned access on 64 bit architecture
339          */
340         rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
341         rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
342         rid->port_id =   pg0->PortIdentifier;
343         rid->roles = FC_RPORT_ROLE_UNKNOWN;
344
345         return 0;
346 }
347
348 static void
349 mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
350 {
351         struct fc_rport_identifiers rport_ids;
352         struct fc_rport         *rport;
353         struct mptfc_rport_info *ri;
354         int                     new_ri = 1;
355         u64                     pn, nn;
356         VirtTarget              *vtarget;
357         u32                     roles = FC_RPORT_ROLE_UNKNOWN;
358
359         if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
360                 return;
361
362         roles |= FC_RPORT_ROLE_FCP_TARGET;
363         if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
364                 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
365
366         /* scan list looking for a match */
367         list_for_each_entry(ri, &ioc->fc_rports, list) {
368                 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
369                 if (pn == rport_ids.port_name) {        /* match */
370                         list_move_tail(&ri->list, &ioc->fc_rports);
371                         new_ri = 0;
372                         break;
373                 }
374         }
375         if (new_ri) {   /* allocate one */
376                 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
377                 if (!ri)
378                         return;
379                 list_add_tail(&ri->list, &ioc->fc_rports);
380         }
381
382         ri->pg0 = *pg0; /* add/update pg0 data */
383         ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
384
385         /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
386         if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
387                 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
388                 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
389                 if (rport) {
390                         ri->rport = rport;
391                         if (new_ri) /* may have been reset by user */
392                                 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
393                         /*
394                          * if already mapped, remap here.  If not mapped,
395                          * target_alloc will allocate vtarget and map,
396                          * slave_alloc will fill in vdev from vtarget.
397                          */
398                         if (ri->starget) {
399                                 vtarget = ri->starget->hostdata;
400                                 if (vtarget) {
401                                         vtarget->target_id = pg0->CurrentTargetID;
402                                         vtarget->bus_id = pg0->CurrentBus;
403                                 }
404                         }
405                         *((struct mptfc_rport_info **)rport->dd_data) = ri;
406                         /* scan will be scheduled once rport becomes a target */
407                         fc_remote_port_rolechg(rport,roles);
408
409                         pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
410                         nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
411                         dfcprintk ((MYIOC_s_INFO_FMT
412                                 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
413                                 "rport tid %d, tmo %d\n",
414                                         ioc->name,
415                                         ioc->sh->host_no,
416                                         pg0->PortIdentifier,
417                                         (unsigned long long)nn,
418                                         (unsigned long long)pn,
419                                         pg0->CurrentTargetID,
420                                         ri->rport->scsi_target_id,
421                                         ri->rport->dev_loss_tmo));
422                 } else {
423                         list_del(&ri->list);
424                         kfree(ri);
425                         ri = NULL;
426                 }
427         }
428 }
429
430 /*
431  *      OS entry point to allow for host driver to free allocated memory
432  *      Called if no device present or device being unloaded
433  */
434 static void
435 mptfc_target_destroy(struct scsi_target *starget)
436 {
437         struct fc_rport         *rport;
438         struct mptfc_rport_info *ri;
439
440         rport = starget_to_rport(starget);
441         if (rport) {
442                 ri = *((struct mptfc_rport_info **)rport->dd_data);
443                 if (ri) /* better be! */
444                         ri->starget = NULL;
445         }
446         if (starget->hostdata)
447                 kfree(starget->hostdata);
448         starget->hostdata = NULL;
449 }
450
451 /*
452  *      OS entry point to allow host driver to alloc memory
453  *      for each scsi target. Called once per device the bus scan.
454  *      Return non-zero if allocation fails.
455  */
456 static int
457 mptfc_target_alloc(struct scsi_target *starget)
458 {
459         VirtTarget              *vtarget;
460         struct fc_rport         *rport;
461         struct mptfc_rport_info *ri;
462         int                     rc;
463
464         vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
465         if (!vtarget)
466                 return -ENOMEM;
467         starget->hostdata = vtarget;
468
469         rc = -ENODEV;
470         rport = starget_to_rport(starget);
471         if (rport) {
472                 ri = *((struct mptfc_rport_info **)rport->dd_data);
473                 if (ri) {       /* better be! */
474                         vtarget->target_id = ri->pg0.CurrentTargetID;
475                         vtarget->bus_id = ri->pg0.CurrentBus;
476                         ri->starget = starget;
477                         rc = 0;
478                 }
479         }
480         if (rc != 0) {
481                 kfree(vtarget);
482                 starget->hostdata = NULL;
483         }
484
485         return rc;
486 }
487
488 /*
489  *      OS entry point to allow host driver to alloc memory
490  *      for each scsi device. Called once per device the bus scan.
491  *      Return non-zero if allocation fails.
492  *      Init memory once per LUN.
493  */
494 static int
495 mptfc_slave_alloc(struct scsi_device *sdev)
496 {
497         MPT_SCSI_HOST           *hd;
498         VirtTarget              *vtarget;
499         VirtDevice              *vdev;
500         struct scsi_target      *starget;
501         struct fc_rport         *rport;
502
503
504         starget = scsi_target(sdev);
505         rport = starget_to_rport(starget);
506
507         if (!rport || fc_remote_port_chkready(rport))
508                 return -ENXIO;
509
510         hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
511
512         vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
513         if (!vdev) {
514                 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
515                                 hd->ioc->name, sizeof(VirtDevice));
516                 return -ENOMEM;
517         }
518
519
520         sdev->hostdata = vdev;
521         vtarget = starget->hostdata;
522
523         if (vtarget->num_luns == 0) {
524                 vtarget->ioc_id = hd->ioc->id;
525                 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
526                                   MPT_TARGET_FLAGS_VALID_INQUIRY;
527                 hd->Targets[sdev->id] = vtarget;
528         }
529
530         vdev->vtarget = vtarget;
531         vdev->lun = sdev->lun;
532
533         vtarget->num_luns++;
534
535
536 #ifdef DMPT_DEBUG_FC
537         {
538         u64 nn, pn;
539         struct mptfc_rport_info *ri;
540         ri = *((struct mptfc_rport_info **)rport->dd_data);
541         pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
542         nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
543         dfcprintk ((MYIOC_s_INFO_FMT
544                 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
545                 "CurrentTargetID %d, %x %llx %llx\n",
546                 hd->ioc->name,
547                 sdev->host->host_no,
548                 vtarget->num_luns,
549                 sdev->id, ri->pg0.CurrentTargetID,
550                 ri->pg0.PortIdentifier,
551                 (unsigned long long)pn,
552                 (unsigned long long)nn));
553         }
554 #endif
555
556         return 0;
557 }
558
559 static int
560 mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
561 {
562         struct mptfc_rport_info *ri;
563         struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
564         int             err;
565
566         err = fc_remote_port_chkready(rport);
567         if (unlikely(err)) {
568                 SCpnt->result = err;
569                 done(SCpnt);
570                 return 0;
571         }
572
573         /* dd_data is null until finished adding target */
574         ri = *((struct mptfc_rport_info **)rport->dd_data);
575         if (unlikely(!ri)) {
576                 dfcprintk ((MYIOC_s_INFO_FMT
577                         "mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
578                         ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
579                         ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
580                         SCpnt->device->id,SCpnt->device->lun));
581                 SCpnt->result = DID_IMM_RETRY << 16;
582                 done(SCpnt);
583                 return 0;
584         }
585
586         err = mptscsih_qcmd(SCpnt,done);
587 #ifdef DMPT_DEBUG_FC
588         if (unlikely(err)) {
589                 dfcprintk ((MYIOC_s_INFO_FMT
590                         "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n",
591                         ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
592                         ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
593                         SCpnt->device->id,SCpnt->device->lun));
594         }
595 #endif
596         return err;
597 }
598
599 /*
600  *      mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
601  *      @ioc: Pointer to MPT_ADAPTER structure
602  *      @portnum: IOC Port number
603  *
604  *      Return: 0 for success
605  *      -ENOMEM if no memory available
606  *              -EPERM if not allowed due to ISR context
607  *              -EAGAIN if no msg frames currently available
608  *              -EFAULT for non-successful reply or no reply (timeout)
609  *              -EINVAL portnum arg out of range (hardwired to two elements)
610  */
611 static int
612 mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
613 {
614         ConfigPageHeader_t       hdr;
615         CONFIGPARMS              cfg;
616         FCPortPage0_t           *ppage0_alloc;
617         FCPortPage0_t           *pp0dest;
618         dma_addr_t               page0_dma;
619         int                      data_sz;
620         int                      copy_sz;
621         int                      rc;
622         int                      count = 400;
623
624         if (portnum > 1)
625                 return -EINVAL;
626
627         /* Get FCPort Page 0 header */
628         hdr.PageVersion = 0;
629         hdr.PageLength = 0;
630         hdr.PageNumber = 0;
631         hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT;
632         cfg.cfghdr.hdr = &hdr;
633         cfg.physAddr = -1;
634         cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
635         cfg.dir = 0;
636         cfg.pageAddr = portnum;
637         cfg.timeout = 0;
638
639         if ((rc = mpt_config(ioc, &cfg)) != 0)
640                 return rc;
641
642         if (hdr.PageLength == 0)
643                 return 0;
644
645         data_sz = hdr.PageLength * 4;
646         rc = -ENOMEM;
647         ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
648         if (ppage0_alloc) {
649
650  try_again:
651                 memset((u8 *)ppage0_alloc, 0, data_sz);
652                 cfg.physAddr = page0_dma;
653                 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
654
655                 if ((rc = mpt_config(ioc, &cfg)) == 0) {
656                         /* save the data */
657                         pp0dest = &ioc->fc_port_page0[portnum];
658                         copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz);
659                         memcpy(pp0dest, ppage0_alloc, copy_sz);
660
661                         /*
662                          *      Normalize endianness of structure data,
663                          *      by byte-swapping all > 1 byte fields!
664                          */
665                         pp0dest->Flags = le32_to_cpu(pp0dest->Flags);
666                         pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier);
667                         pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low);
668                         pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High);
669                         pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low);
670                         pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High);
671                         pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass);
672                         pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds);
673                         pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed);
674                         pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize);
675                         pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low);
676                         pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High);
677                         pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low);
678                         pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High);
679                         pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
680                         pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
681
682                         /*
683                          * if still doing discovery,
684                          * hang loose a while until finished
685                          */
686                         if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
687                                 if (count-- > 0) {
688                                         msleep_interruptible(100);
689                                         goto try_again;
690                                 }
691                                 printk(MYIOC_s_INFO_FMT "Firmware discovery not"
692                                                         " complete.\n",
693                                                 ioc->name);
694                         }
695                 }
696
697                 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
698         }
699
700         return rc;
701 }
702
703 static void
704 mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
705 {
706         unsigned class = 0, cos = 0;
707
708         /* don't know what to do as only one scsi (fc) host was allocated */
709         if (portnum != 0)
710                 return;
711
712         class = ioc->fc_port_page0[portnum].SupportedServiceClass;
713         if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
714                 cos |= FC_COS_CLASS1;
715         if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
716                 cos |= FC_COS_CLASS2;
717         if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
718                 cos |= FC_COS_CLASS3;
719
720         fc_host_node_name(ioc->sh) =
721                 (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
722                     | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
723
724         fc_host_port_name(ioc->sh) =
725                 (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
726                     | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
727
728         fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
729
730         fc_host_supported_classes(ioc->sh) = cos;
731
732         fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
733 }
734
735 static void
736 mptfc_rescan_devices(void *arg)
737 {
738         MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
739         int                     ii;
740         int                     work_to_do;
741         u64                     pn;
742         unsigned long           flags;
743         struct mptfc_rport_info *ri;
744
745         do {
746                 /* start by tagging all ports as missing */
747                 list_for_each_entry(ri, &ioc->fc_rports, list) {
748                         if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
749                                 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
750                         }
751                 }
752
753                 /*
754                  * now rescan devices known to adapter,
755                  * will reregister existing rports
756                  */
757                 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
758                         (void) mptfc_GetFcPortPage0(ioc, ii);
759                         mptfc_init_host_attr(ioc,ii);   /* refresh */
760                         mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
761                 }
762
763                 /* delete devices still missing */
764                 list_for_each_entry(ri, &ioc->fc_rports, list) {
765                         /* if newly missing, delete it */
766                         if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
767
768                                 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
769                                                MPT_RPORT_INFO_FLAGS_MISSING);
770                                 fc_remote_port_delete(ri->rport);       /* won't sleep */
771                                 ri->rport = NULL;
772
773                                 pn = (u64)ri->pg0.WWPN.High << 32 |
774                                      (u64)ri->pg0.WWPN.Low;
775                                 dfcprintk ((MYIOC_s_INFO_FMT
776                                         "mptfc_rescan.%d: %llx deleted\n",
777                                         ioc->name,
778                                         ioc->sh->host_no,
779                                         (unsigned long long)pn));
780                         }
781                 }
782
783                 /*
784                  * allow multiple passes as target state
785                  * might have changed during scan
786                  */
787                 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
788                 if (ioc->fc_rescan_work_count > 2)      /* only need one more */
789                         ioc->fc_rescan_work_count = 2;
790                 work_to_do = --ioc->fc_rescan_work_count;
791                 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
792         } while (work_to_do);
793 }
794
795 static int
796 mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
797 {
798         struct Scsi_Host        *sh;
799         MPT_SCSI_HOST           *hd;
800         MPT_ADAPTER             *ioc;
801         unsigned long            flags;
802         int                      ii;
803         int                      numSGE = 0;
804         int                      scale;
805         int                      ioc_cap;
806         int                     error=0;
807         int                     r;
808
809         if ((r = mpt_attach(pdev,id)) != 0)
810                 return r;
811
812         ioc = pci_get_drvdata(pdev);
813         ioc->DoneCtx = mptfcDoneCtx;
814         ioc->TaskCtx = mptfcTaskCtx;
815         ioc->InternalCtx = mptfcInternalCtx;
816
817         /*  Added sanity check on readiness of the MPT adapter.
818          */
819         if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
820                 printk(MYIOC_s_WARN_FMT
821                   "Skipping because it's not operational!\n",
822                   ioc->name);
823                 error = -ENODEV;
824                 goto out_mptfc_probe;
825         }
826
827         if (!ioc->active) {
828                 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
829                   ioc->name);
830                 error = -ENODEV;
831                 goto out_mptfc_probe;
832         }
833
834         /*  Sanity check - ensure at least 1 port is INITIATOR capable
835          */
836         ioc_cap = 0;
837         for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
838                 if (ioc->pfacts[ii].ProtocolFlags &
839                     MPI_PORTFACTS_PROTOCOL_INITIATOR)
840                         ioc_cap ++;
841         }
842
843         if (!ioc_cap) {
844                 printk(MYIOC_s_WARN_FMT
845                         "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
846                         ioc->name, ioc);
847                 return -ENODEV;
848         }
849
850         sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
851
852         if (!sh) {
853                 printk(MYIOC_s_WARN_FMT
854                         "Unable to register controller with SCSI subsystem\n",
855                         ioc->name);
856                 error = -1;
857                 goto out_mptfc_probe;
858         }
859
860         spin_lock_init(&ioc->fc_rescan_work_lock);
861         INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
862
863         spin_lock_irqsave(&ioc->FreeQlock, flags);
864
865         /* Attach the SCSI Host to the IOC structure
866          */
867         ioc->sh = sh;
868
869         sh->io_port = 0;
870         sh->n_io_port = 0;
871         sh->irq = 0;
872
873         /* set 16 byte cdb's */
874         sh->max_cmd_len = 16;
875
876         sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
877
878         sh->max_lun = MPT_LAST_LUN + 1;
879         sh->max_channel = 0;
880         sh->this_id = ioc->pfacts[0].PortSCSIID;
881
882         /* Required entry.
883          */
884         sh->unique_id = ioc->id;
885
886         /* Verify that we won't exceed the maximum
887          * number of chain buffers
888          * We can optimize:  ZZ = req_sz/sizeof(SGE)
889          * For 32bit SGE's:
890          *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
891          *               + (req_sz - 64)/sizeof(SGE)
892          * A slightly different algorithm is required for
893          * 64bit SGEs.
894          */
895         scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
896         if (sizeof(dma_addr_t) == sizeof(u64)) {
897                 numSGE = (scale - 1) *
898                   (ioc->facts.MaxChainDepth-1) + scale +
899                   (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
900                   sizeof(u32));
901         } else {
902                 numSGE = 1 + (scale - 1) *
903                   (ioc->facts.MaxChainDepth-1) + scale +
904                   (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
905                   sizeof(u32));
906         }
907
908         if (numSGE < sh->sg_tablesize) {
909                 /* Reset this value */
910                 dprintk((MYIOC_s_INFO_FMT
911                   "Resetting sg_tablesize to %d from %d\n",
912                   ioc->name, numSGE, sh->sg_tablesize));
913                 sh->sg_tablesize = numSGE;
914         }
915
916         spin_unlock_irqrestore(&ioc->FreeQlock, flags);
917
918         hd = (MPT_SCSI_HOST *) sh->hostdata;
919         hd->ioc = ioc;
920
921         /* SCSI needs scsi_cmnd lookup table!
922          * (with size equal to req_depth*PtrSz!)
923          */
924         hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
925         if (!hd->ScsiLookup) {
926                 error = -ENOMEM;
927                 goto out_mptfc_probe;
928         }
929
930         dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
931                  ioc->name, hd->ScsiLookup));
932
933         /* Allocate memory for the device structures.
934          * A non-Null pointer at an offset
935          * indicates a device exists.
936          * max_id = 1 + maximum id (hosts.h)
937          */
938         hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
939         if (!hd->Targets) {
940                 error = -ENOMEM;
941                 goto out_mptfc_probe;
942         }
943
944         dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
945
946         /* Clear the TM flags
947          */
948         hd->tmPending = 0;
949         hd->tmState = TM_STATE_NONE;
950         hd->resetPending = 0;
951         hd->abortSCpnt = NULL;
952
953         /* Clear the pointer used to store
954          * single-threaded commands, i.e., those
955          * issued during a bus scan, dv and
956          * configuration pages.
957          */
958         hd->cmdPtr = NULL;
959
960         /* Initialize this SCSI Hosts' timers
961          * To use, set the timer expires field
962          * and add_timer
963          */
964         init_timer(&hd->timer);
965         hd->timer.data = (unsigned long) hd;
966         hd->timer.function = mptscsih_timer_expired;
967
968         hd->mpt_pq_filter = mpt_pq_filter;
969
970         ddvprintk((MYIOC_s_INFO_FMT
971                 "mpt_pq_filter %x\n",
972                 ioc->name, 
973                 mpt_pq_filter));
974
975         init_waitqueue_head(&hd->scandv_waitq);
976         hd->scandv_wait_done = 0;
977         hd->last_queue_full = 0;
978
979         sh->transportt = mptfc_transport_template;
980         error = scsi_add_host (sh, &ioc->pcidev->dev);
981         if(error) {
982                 dprintk((KERN_ERR MYNAM
983                   "scsi_add_host failed\n"));
984                 goto out_mptfc_probe;
985         }
986
987         /* initialize workqueue */
988
989         snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d",
990                 sh->host_no);
991         ioc->fc_rescan_work_q =
992                 create_singlethread_workqueue(ioc->fc_rescan_work_q_name);
993         if (!ioc->fc_rescan_work_q)
994                 goto out_mptfc_probe;
995
996         /*
997          *  Pre-fetch FC port WWN and stuff...
998          *  (FCPortPage0_t stuff)
999          */
1000         for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
1001                 (void) mptfc_GetFcPortPage0(ioc, ii);
1002         }
1003
1004         /*
1005          * scan for rports -
1006          *      by doing it via the workqueue, some locking is eliminated
1007          */
1008
1009         ioc->fc_rescan_work_count = 1;
1010         queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
1011         flush_workqueue(ioc->fc_rescan_work_q);
1012
1013         return 0;
1014
1015 out_mptfc_probe:
1016
1017         mptscsih_remove(pdev);
1018         return error;
1019 }
1020
1021 static struct pci_driver mptfc_driver = {
1022         .name           = "mptfc",
1023         .id_table       = mptfc_pci_table,
1024         .probe          = mptfc_probe,
1025         .remove         = __devexit_p(mptfc_remove),
1026         .shutdown       = mptscsih_shutdown,
1027 #ifdef CONFIG_PM
1028         .suspend        = mptscsih_suspend,
1029         .resume         = mptscsih_resume,
1030 #endif
1031 };
1032
1033 static int
1034 mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
1035 {
1036         MPT_SCSI_HOST *hd;
1037         u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
1038         unsigned long flags;
1039         int rc=1;
1040
1041         devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
1042                         ioc->name, event));
1043
1044         if (ioc->sh == NULL ||
1045                 ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
1046                 return 1;
1047
1048         switch (event) {
1049         case MPI_EVENT_RESCAN:
1050                 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1051                 if (ioc->fc_rescan_work_q) {
1052                         if (ioc->fc_rescan_work_count++ == 0) {
1053                                 queue_work(ioc->fc_rescan_work_q,
1054                                            &ioc->fc_rescan_work);
1055                         }
1056                 }
1057                 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1058                 break;
1059         default:
1060                 rc = mptscsih_event_process(ioc,pEvReply);
1061                 break;
1062         }
1063         return rc;
1064 }
1065
1066 static int
1067 mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1068 {
1069         int             rc;
1070         unsigned long   flags;
1071
1072         rc = mptscsih_ioc_reset(ioc,reset_phase);
1073         if (rc == 0)
1074                 return rc;
1075
1076
1077         dtmprintk((KERN_WARNING MYNAM
1078                 ": IOC %s_reset routed to FC host driver!\n",
1079                 reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
1080                 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
1081
1082         if (reset_phase == MPT_IOC_SETUP_RESET) {
1083         }
1084
1085         else if (reset_phase == MPT_IOC_PRE_RESET) {
1086         }
1087
1088         else {  /* MPT_IOC_POST_RESET */
1089                 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1090                 if (ioc->fc_rescan_work_q) {
1091                         if (ioc->fc_rescan_work_count++ == 0) {
1092                                 queue_work(ioc->fc_rescan_work_q,
1093                                            &ioc->fc_rescan_work);
1094                         }
1095                 }
1096                 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1097         }
1098         return 1;
1099 }
1100
1101 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1102 /**
1103  *      mptfc_init - Register MPT adapter(s) as SCSI host(s) with
1104  *      linux scsi mid-layer.
1105  *
1106  *      Returns 0 for success, non-zero for failure.
1107  */
1108 static int __init
1109 mptfc_init(void)
1110 {
1111         int error;
1112
1113         show_mptmod_ver(my_NAME, my_VERSION);
1114
1115         /* sanity check module parameter */
1116         if (mptfc_dev_loss_tmo == 0)
1117                 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
1118
1119         mptfc_transport_template =
1120                 fc_attach_transport(&mptfc_transport_functions);
1121
1122         if (!mptfc_transport_template)
1123                 return -ENODEV;
1124
1125         mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
1126         mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
1127         mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
1128
1129         if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
1130                 devtverboseprintk((KERN_INFO MYNAM
1131                   ": Registered for IOC event notifications\n"));
1132         }
1133
1134         if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
1135                 dprintk((KERN_INFO MYNAM
1136                   ": Registered for IOC reset notifications\n"));
1137         }
1138
1139         error = pci_register_driver(&mptfc_driver);
1140         if (error)
1141                 fc_release_transport(mptfc_transport_template);
1142
1143         return error;
1144 }
1145
1146 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1147 /**
1148  *      mptfc_remove - Removed fc infrastructure for devices
1149  *      @pdev: Pointer to pci_dev structure
1150  *
1151  */
1152 static void __devexit
1153 mptfc_remove(struct pci_dev *pdev)
1154 {
1155         MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
1156         struct mptfc_rport_info *p, *n;
1157         struct workqueue_struct *work_q;
1158         unsigned long           flags;
1159
1160         /* destroy workqueue */
1161         if ((work_q=ioc->fc_rescan_work_q)) {
1162                 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
1163                 ioc->fc_rescan_work_q = NULL;
1164                 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
1165                 destroy_workqueue(work_q);
1166         }
1167
1168         fc_remove_host(ioc->sh);
1169
1170         list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
1171                 list_del(&p->list);
1172                 kfree(p);
1173         }
1174
1175         mptscsih_remove(pdev);
1176 }
1177
1178 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1179 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1180 /**
1181  *      mptfc_exit - Unregisters MPT adapter(s)
1182  *
1183  */
1184 static void __exit
1185 mptfc_exit(void)
1186 {
1187         pci_unregister_driver(&mptfc_driver);
1188         fc_release_transport(mptfc_transport_template);
1189
1190         mpt_reset_deregister(mptfcDoneCtx);
1191         dprintk((KERN_INFO MYNAM
1192           ": Deregistered for IOC reset notifications\n"));
1193
1194         mpt_event_deregister(mptfcDoneCtx);
1195         dprintk((KERN_INFO MYNAM
1196           ": Deregistered for IOC event notifications\n"));
1197
1198         mpt_deregister(mptfcInternalCtx);
1199         mpt_deregister(mptfcTaskCtx);
1200         mpt_deregister(mptfcDoneCtx);
1201 }
1202
1203 module_init(mptfc_init);
1204 module_exit(mptfc_exit);