[SCSI] mptfusion: move fc event/reset handling to mptfc
[deliverable/linux.git] / drivers / message / fusion / mptfc.c
CommitLineData
2496af39
MED
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>
05e8ec17 58#include <linux/sort.h>
2496af39
MED
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>
05e8ec17 65#include <scsi/scsi_transport_fc.h>
2496af39
MED
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
75MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
78
79/* Command line args */
80static int mpt_pq_filter = 0;
81module_param(mpt_pq_filter, int, 0);
82MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
83
05e8ec17
MR
84#define MPTFC_DEV_LOSS_TMO (60)
85static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
86module_param(mptfc_dev_loss_tmo, int, 0);
87MODULE_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
2496af39
MED
92static int mptfcDoneCtx = -1;
93static int mptfcTaskCtx = -1;
94static int mptfcInternalCtx = -1; /* Used only for internal commands */
95
3bc7bf1d
MR
96static int mptfc_target_alloc(struct scsi_target *starget);
97static int mptfc_slave_alloc(struct scsi_device *sdev);
05e8ec17 98static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
3bc7bf1d
MR
99 void (*done)(struct scsi_cmnd *));
100static void mptfc_target_destroy(struct scsi_target *starget);
05e8ec17
MR
101static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
102static void __devexit mptfc_remove(struct pci_dev *pdev);
103
2496af39 104static struct scsi_host_template mptfc_driver_template = {
f78496da 105 .module = THIS_MODULE,
2496af39
MED
106 .proc_name = "mptfc",
107 .proc_info = mptscsih_proc_info,
108 .name = "MPT FC Host",
109 .info = mptscsih_info,
05e8ec17 110 .queuecommand = mptfc_qcmd,
3bc7bf1d 111 .target_alloc = mptfc_target_alloc,
05e8ec17 112 .slave_alloc = mptfc_slave_alloc,
2496af39 113 .slave_configure = mptscsih_slave_configure,
3bc7bf1d 114 .target_destroy = mptfc_target_destroy,
2496af39 115 .slave_destroy = mptscsih_slave_destroy,
6e3815ba 116 .change_queue_depth = mptscsih_change_queue_depth,
2496af39
MED
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,
2496af39
MED
128};
129
130/****************************************************************************
131 * Supported hardware
132 */
133
134static 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 },
3fadc59d
MED
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 },
6d5b0c31
ME
149 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
150 PCI_ANY_ID, PCI_ANY_ID },
2496af39
MED
151 {0} /* Terminating entry */
152};
153MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
154
05e8ec17
MR
155static struct scsi_transport_template *mptfc_transport_template = NULL;
156
03fbcbcd 157static struct fc_function_template mptfc_transport_functions = {
05e8ec17
MR
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 */
179static void
180mptfc_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
188static int
189mptfc_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
206static int
207mptfc_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
322static int
323mptfc_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;
05e8ec17
MR
344
345 return 0;
346}
347
348static void
349mptfc_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;
3bc7bf1d 354 int new_ri = 1;
65207fed 355 u64 pn, nn;
3bc7bf1d 356 VirtTarget *vtarget;
6dd727da 357 u32 roles = FC_RPORT_ROLE_UNKNOWN;
05e8ec17
MR
358
359 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
360 return;
361
6dd727da 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
05e8ec17 366 /* scan list looking for a match */
05e8ec17 367 list_for_each_entry(ri, &ioc->fc_rports, list) {
3bc7bf1d
MR
368 pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
369 if (pn == rport_ids.port_name) { /* match */
05e8ec17 370 list_move_tail(&ri->list, &ioc->fc_rports);
3bc7bf1d 371 new_ri = 0;
05e8ec17
MR
372 break;
373 }
374 }
3bc7bf1d 375 if (new_ri) { /* allocate one */
05e8ec17
MR
376 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
377 if (!ri)
378 return;
05e8ec17
MR
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
3bc7bf1d 385 /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
05e8ec17
MR
386 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
387 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
3bc7bf1d 388 rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
05e8ec17 389 if (rport) {
3bc7bf1d
MR
390 ri->rport = rport;
391 if (new_ri) /* may have been reset by user */
392 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
05e8ec17
MR
393 /*
394 * if already mapped, remap here. If not mapped,
3bc7bf1d
MR
395 * target_alloc will allocate vtarget and map,
396 * slave_alloc will fill in vdev from vtarget.
05e8ec17 397 */
3bc7bf1d
MR
398 if (ri->starget) {
399 vtarget = ri->starget->hostdata;
400 if (vtarget) {
401 vtarget->target_id = pg0->CurrentTargetID;
402 vtarget->bus_id = pg0->CurrentBus;
3bc7bf1d 403 }
05e8ec17 404 }
65207fed 405 *((struct mptfc_rport_info **)rport->dd_data) = ri;
6dd727da 406 /* scan will be scheduled once rport becomes a target */
407 fc_remote_port_rolechg(rport,roles);
65207fed
ME
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;
3bc7bf1d
MR
411 dfcprintk ((MYIOC_s_INFO_FMT
412 "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
05e8ec17 413 "rport tid %d, tmo %d\n",
3bc7bf1d 414 ioc->name,
914c2d8e 415 ioc->sh->host_no,
05e8ec17 416 pg0->PortIdentifier,
65207fed
ME
417 (unsigned long long)nn,
418 (unsigned long long)pn,
05e8ec17
MR
419 pg0->CurrentTargetID,
420 ri->rport->scsi_target_id,
3bc7bf1d 421 ri->rport->dev_loss_tmo));
05e8ec17
MR
422 } else {
423 list_del(&ri->list);
424 kfree(ri);
425 ri = NULL;
426 }
427 }
05e8ec17
MR
428}
429
3bc7bf1d
MR
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 */
434static void
435mptfc_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 */
456static int
457mptfc_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;
3bc7bf1d
MR
477 rc = 0;
478 }
479 }
480 if (rc != 0) {
481 kfree(vtarget);
482 starget->hostdata = NULL;
483 }
484
485 return rc;
486}
487
2496af39 488/*
05e8ec17
MR
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.
2496af39 493 */
03fbcbcd 494static int
05e8ec17
MR
495mptfc_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;
05e8ec17
MR
502
503
65207fed
ME
504 starget = scsi_target(sdev);
505 rport = starget_to_rport(starget);
05e8ec17
MR
506
507 if (!rport || fc_remote_port_chkready(rport))
508 return -ENXIO;
509
510 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
511
3bc7bf1d 512 vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
05e8ec17
MR
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 }
05e8ec17 518
05e8ec17 519
05e8ec17 520 sdev->hostdata = vdev;
05e8ec17 521 vtarget = starget->hostdata;
3bc7bf1d 522
05e8ec17 523 if (vtarget->num_luns == 0) {
3bc7bf1d 524 vtarget->ioc_id = hd->ioc->id;
05e8ec17
MR
525 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
526 MPT_TARGET_FLAGS_VALID_INQUIRY;
527 hd->Targets[sdev->id] = vtarget;
528 }
529
05e8ec17 530 vdev->vtarget = vtarget;
05e8ec17 531 vdev->lun = sdev->lun;
05e8ec17 532
05e8ec17
MR
533 vtarget->num_luns++;
534
65207fed 535
914c2d8e 536#ifdef DMPT_DEBUG_FC
65207fed
ME
537 {
538 u64 nn, pn;
914c2d8e
ME
539 struct mptfc_rport_info *ri;
540 ri = *((struct mptfc_rport_info **)rport->dd_data);
65207fed
ME
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;
3bc7bf1d
MR
543 dfcprintk ((MYIOC_s_INFO_FMT
544 "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
05e8ec17 545 "CurrentTargetID %d, %x %llx %llx\n",
914c2d8e 546 hd->ioc->name,
3bc7bf1d
MR
547 sdev->host->host_no,
548 vtarget->num_luns,
549 sdev->id, ri->pg0.CurrentTargetID,
65207fed
ME
550 ri->pg0.PortIdentifier,
551 (unsigned long long)pn,
552 (unsigned long long)nn));
914c2d8e
ME
553 }
554#endif
05e8ec17
MR
555
556 return 0;
557}
558
559static int
560mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
561{
3bc7bf1d 562 struct mptfc_rport_info *ri;
05e8ec17
MR
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 }
65207fed
ME
572
573 /* dd_data is null until finished adding target */
3bc7bf1d 574 ri = *((struct mptfc_rport_info **)rport->dd_data);
65207fed
ME
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 }
3bc7bf1d 585
65207fed
ME
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;
05e8ec17
MR
597}
598
80d3ac77
MR
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 */
611static int
612mptfc_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
05e8ec17
MR
703static void
704mptfc_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
735static void
736mptfc_rescan_devices(void *arg)
737{
738 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
739 int ii;
740 int work_to_do;
65207fed 741 u64 pn;
05e8ec17
MR
742 unsigned long flags;
743 struct mptfc_rport_info *ri;
744
745 do {
746 /* start by tagging all ports as missing */
05e8ec17
MR
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 }
05e8ec17
MR
752
753 /*
754 * now rescan devices known to adapter,
755 * will reregister existing rports
756 */
757 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
80d3ac77 758 (void) mptfc_GetFcPortPage0(ioc, ii);
05e8ec17
MR
759 mptfc_init_host_attr(ioc,ii); /* refresh */
760 mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
761 }
762
763 /* delete devices still missing */
05e8ec17
MR
764 list_for_each_entry(ri, &ioc->fc_rports, list) {
765 /* if newly missing, delete it */
65207fed 766 if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
05e8ec17
MR
767
768 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
769 MPT_RPORT_INFO_FLAGS_MISSING);
65207fed 770 fc_remote_port_delete(ri->rport); /* won't sleep */
3bc7bf1d 771 ri->rport = NULL;
65207fed
ME
772
773 pn = (u64)ri->pg0.WWPN.High << 32 |
774 (u64)ri->pg0.WWPN.Low;
3bc7bf1d
MR
775 dfcprintk ((MYIOC_s_INFO_FMT
776 "mptfc_rescan.%d: %llx deleted\n",
777 ioc->name,
778 ioc->sh->host_no,
65207fed 779 (unsigned long long)pn));
05e8ec17
MR
780 }
781 }
05e8ec17
MR
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
2496af39
MED
795static int
796mptfc_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;
1ca00bb7 802 int ii;
2496af39
MED
803 int numSGE = 0;
804 int scale;
805 int ioc_cap;
2496af39
MED
806 int error=0;
807 int r;
05e8ec17 808
2496af39
MED
809 if ((r = mpt_attach(pdev,id)) != 0)
810 return r;
05e8ec17 811
2496af39 812 ioc = pci_get_drvdata(pdev);
d335cc38
MED
813 ioc->DoneCtx = mptfcDoneCtx;
814 ioc->TaskCtx = mptfcTaskCtx;
815 ioc->InternalCtx = mptfcInternalCtx;
2496af39
MED
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);
7acec1e7
MED
823 error = -ENODEV;
824 goto out_mptfc_probe;
2496af39
MED
825 }
826
827 if (!ioc->active) {
828 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
829 ioc->name);
7acec1e7
MED
830 error = -ENODEV;
831 goto out_mptfc_probe;
2496af39
MED
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);
05e8ec17 847 return -ENODEV;
2496af39
MED
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);
7acec1e7
MED
856 error = -1;
857 goto out_mptfc_probe;
2496af39
MED
858 }
859
80d3ac77 860 spin_lock_init(&ioc->fc_rescan_work_lock);
05e8ec17
MR
861 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
862
2496af39
MED
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
2496af39
MED
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 */
1ca00bb7
CH
924 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
925 if (!hd->ScsiLookup) {
2496af39 926 error = -ENOMEM;
7acec1e7 927 goto out_mptfc_probe;
2496af39
MED
928 }
929
1ca00bb7
CH
930 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
931 ioc->name, hd->ScsiLookup));
2496af39
MED
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 */
1ca00bb7
CH
938 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
939 if (!hd->Targets) {
2496af39 940 error = -ENOMEM;
7acec1e7 941 goto out_mptfc_probe;
2496af39
MED
942 }
943
1ca00bb7 944 dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
2496af39
MED
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
2496af39
MED
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
05e8ec17 979 sh->transportt = mptfc_transport_template;
2496af39
MED
980 error = scsi_add_host (sh, &ioc->pcidev->dev);
981 if(error) {
982 dprintk((KERN_ERR MYNAM
983 "scsi_add_host failed\n"));
7acec1e7 984 goto out_mptfc_probe;
2496af39
MED
985 }
986
65207fed
ME
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
80d3ac77
MR
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
65207fed
ME
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);
05e8ec17 1012
2496af39
MED
1013 return 0;
1014
7acec1e7 1015out_mptfc_probe:
2496af39
MED
1016
1017 mptscsih_remove(pdev);
1018 return error;
1019}
1020
1021static struct pci_driver mptfc_driver = {
1022 .name = "mptfc",
1023 .id_table = mptfc_pci_table,
1024 .probe = mptfc_probe,
05e8ec17 1025 .remove = __devexit_p(mptfc_remove),
d18c3db5 1026 .shutdown = mptscsih_shutdown,
2496af39
MED
1027#ifdef CONFIG_PM
1028 .suspend = mptscsih_suspend,
1029 .resume = mptscsih_resume,
1030#endif
1031};
1032
80d3ac77
MR
1033static int
1034mptfc_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
1066static int
1067mptfc_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
2496af39
MED
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 */
1108static int __init
1109mptfc_init(void)
1110{
05e8ec17 1111 int error;
2496af39
MED
1112
1113 show_mptmod_ver(my_NAME, my_VERSION);
1114
05e8ec17
MR
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
2496af39
MED
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
80d3ac77 1129 if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
3a892bef 1130 devtverboseprintk((KERN_INFO MYNAM
2496af39
MED
1131 ": Registered for IOC event notifications\n"));
1132 }
1133
80d3ac77 1134 if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
2496af39
MED
1135 dprintk((KERN_INFO MYNAM
1136 ": Registered for IOC reset notifications\n"));
1137 }
1138
05e8ec17 1139 error = pci_register_driver(&mptfc_driver);
3bc7bf1d 1140 if (error)
05e8ec17 1141 fc_release_transport(mptfc_transport_template);
05e8ec17
MR
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 */
3bc7bf1d
MR
1152static void __devexit
1153mptfc_remove(struct pci_dev *pdev)
05e8ec17 1154{
65207fed
ME
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 }
05e8ec17
MR
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);
2496af39
MED
1176}
1177
1178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1180/**
1181 * mptfc_exit - Unregisters MPT adapter(s)
1182 *
1183 */
1184static void __exit
1185mptfc_exit(void)
1186{
1187 pci_unregister_driver(&mptfc_driver);
05e8ec17
MR
1188 fc_release_transport(mptfc_transport_template);
1189
2496af39
MED
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
1203module_init(mptfc_init);
1204module_exit(mptfc_exit);
This page took 0.285151 seconds and 5 git commands to generate.