blob: a380fe105a226121484a868f226b5d5b386f6ac3 [file] [log] [blame]
Moore, Eric Dean 2496af32005-04-22 18:02:41 -04001/*
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>
Michael Reed05e8ec12006-01-13 14:31:54 -060058#include <linux/sort.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040059
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>
Michael Reed05e8ec12006-01-13 14:31:54 -060065#include <scsi/scsi_transport_fc.h>
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040066
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
Michael Reed05e8ec12006-01-13 14:31:54 -060084#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
Moore, Eric Dean 2496af32005-04-22 18:02:41 -040092static int mptfcDoneCtx = -1;
93static int mptfcTaskCtx = -1;
94static int mptfcInternalCtx = -1; /* Used only for internal commands */
95
Michael Reed05e8ec12006-01-13 14:31:54 -060096int mptfc_slave_alloc(struct scsi_device *device);
97static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
98 void (*done)(struct scsi_cmnd *));
99
100static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
101static void __devexit mptfc_remove(struct pci_dev *pdev);
102
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400103static struct scsi_host_template mptfc_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -0700104 .module = THIS_MODULE,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400105 .proc_name = "mptfc",
106 .proc_info = mptscsih_proc_info,
107 .name = "MPT FC Host",
108 .info = mptscsih_info,
Michael Reed05e8ec12006-01-13 14:31:54 -0600109 .queuecommand = mptfc_qcmd,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700110 .target_alloc = mptscsih_target_alloc,
Michael Reed05e8ec12006-01-13 14:31:54 -0600111 .slave_alloc = mptfc_slave_alloc,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400112 .slave_configure = mptscsih_slave_configure,
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700113 .target_destroy = mptscsih_target_destroy,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400114 .slave_destroy = mptscsih_slave_destroy,
Moore, Eric Dean6e3815b2005-06-24 12:18:57 -0600115 .change_queue_depth = mptscsih_change_queue_depth,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400116 .eh_abort_handler = mptscsih_abort,
117 .eh_device_reset_handler = mptscsih_dev_reset,
118 .eh_bus_reset_handler = mptscsih_bus_reset,
119 .eh_host_reset_handler = mptscsih_host_reset,
120 .bios_param = mptscsih_bios_param,
121 .can_queue = MPT_FC_CAN_QUEUE,
122 .this_id = -1,
123 .sg_tablesize = MPT_SCSI_SG_DEPTH,
124 .max_sectors = 8192,
125 .cmd_per_lun = 7,
126 .use_clustering = ENABLE_CLUSTERING,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400127};
128
129/****************************************************************************
130 * Supported hardware
131 */
132
133static struct pci_device_id mptfc_pci_table[] = {
134 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909,
135 PCI_ANY_ID, PCI_ANY_ID },
136 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919,
137 PCI_ANY_ID, PCI_ANY_ID },
138 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929,
139 PCI_ANY_ID, PCI_ANY_ID },
140 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X,
141 PCI_ANY_ID, PCI_ANY_ID },
142 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X,
143 PCI_ANY_ID, PCI_ANY_ID },
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600144 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X,
145 PCI_ANY_ID, PCI_ANY_ID },
146 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
147 PCI_ANY_ID, PCI_ANY_ID },
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400148 {0} /* Terminating entry */
149};
150MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
151
Michael Reed05e8ec12006-01-13 14:31:54 -0600152static struct scsi_transport_template *mptfc_transport_template = NULL;
153
154struct fc_function_template mptfc_transport_functions = {
155 .dd_fcrport_size = 8,
156 .show_host_node_name = 1,
157 .show_host_port_name = 1,
158 .show_host_supported_classes = 1,
159 .show_host_port_id = 1,
160 .show_rport_supported_classes = 1,
161 .show_starget_node_name = 1,
162 .show_starget_port_name = 1,
163 .show_starget_port_id = 1,
164 .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
165 .show_rport_dev_loss_tmo = 1,
166
167};
168
169/* FIXME! values controlling firmware RESCAN event
170 * need to be set low to allow dev_loss_tmo to
171 * work as expected. Currently, firmware doesn't
172 * notify driver of RESCAN event until some number
173 * of seconds elapse. This value can be set via
174 * lsiutil.
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400175 */
Michael Reed05e8ec12006-01-13 14:31:54 -0600176static void
177mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
178{
179 if (timeout > 0)
180 rport->dev_loss_tmo = timeout;
181 else
182 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
183}
184
185static int
186mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
187{
188 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
189 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
190
191 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
192 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
193 return 0;
194 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
195 return -1;
196 return 1;
197 }
198 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
199 return -1;
200 return 1;
201}
202
203static int
204mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
205 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
206{
207 ConfigPageHeader_t hdr;
208 CONFIGPARMS cfg;
209 FCDevicePage0_t *ppage0_alloc, *fc;
210 dma_addr_t page0_dma;
211 int data_sz;
212 int ii;
213
214 FCDevicePage0_t *p0_array=NULL, *p_p0;
215 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
216
217 int rc = -ENOMEM;
218 U32 port_id = 0xffffff;
219 int num_targ = 0;
220 int max_bus = ioc->facts.MaxBuses;
221 int max_targ = ioc->facts.MaxDevices;
222
223 if (max_bus == 0 || max_targ == 0)
224 goto out;
225
226 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
227 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
228 if (!p0_array)
229 goto out;
230
231 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
232 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
233 if (!pp0_array)
234 goto out;
235
236 do {
237 /* Get FC Device Page 0 header */
238 hdr.PageVersion = 0;
239 hdr.PageLength = 0;
240 hdr.PageNumber = 0;
241 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
242 cfg.cfghdr.hdr = &hdr;
243 cfg.physAddr = -1;
244 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
245 cfg.dir = 0;
246 cfg.pageAddr = port_id;
247 cfg.timeout = 0;
248
249 if ((rc = mpt_config(ioc, &cfg)) != 0)
250 break;
251
252 if (hdr.PageLength <= 0)
253 break;
254
255 data_sz = hdr.PageLength * 4;
256 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
257 &page0_dma);
258 rc = -ENOMEM;
259 if (!ppage0_alloc)
260 break;
261
262 cfg.physAddr = page0_dma;
263 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
264
265 if ((rc = mpt_config(ioc, &cfg)) == 0) {
266 ppage0_alloc->PortIdentifier =
267 le32_to_cpu(ppage0_alloc->PortIdentifier);
268
269 ppage0_alloc->WWNN.Low =
270 le32_to_cpu(ppage0_alloc->WWNN.Low);
271
272 ppage0_alloc->WWNN.High =
273 le32_to_cpu(ppage0_alloc->WWNN.High);
274
275 ppage0_alloc->WWPN.Low =
276 le32_to_cpu(ppage0_alloc->WWPN.Low);
277
278 ppage0_alloc->WWPN.High =
279 le32_to_cpu(ppage0_alloc->WWPN.High);
280
281 ppage0_alloc->BBCredit =
282 le16_to_cpu(ppage0_alloc->BBCredit);
283
284 ppage0_alloc->MaxRxFrameSize =
285 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
286
287 port_id = ppage0_alloc->PortIdentifier;
288 num_targ++;
289 *p_p0 = *ppage0_alloc; /* save data */
290 *p_pp0++ = p_p0++; /* save addr */
291 }
292 pci_free_consistent(ioc->pcidev, data_sz,
293 (u8 *) ppage0_alloc, page0_dma);
294 if (rc != 0)
295 break;
296
297 } while (port_id <= 0xff0000);
298
299 if (num_targ) {
300 /* sort array */
301 if (num_targ > 1)
302 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
303 mptfc_FcDevPage0_cmp_func, NULL);
304 /* call caller's func for each targ */
305 for (ii = 0; ii < num_targ; ii++) {
306 fc = *(pp0_array+ii);
307 func(ioc, ioc_port, fc);
308 }
309 }
310
311 out:
312 if (pp0_array)
313 kfree(pp0_array);
314 if (p0_array)
315 kfree(p0_array);
316 return rc;
317}
318
319static int
320mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
321{
322 /* not currently usable */
323 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
324 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
325 return -1;
326
327 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
328 return -1;
329
330 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
331 return -1;
332
333 /*
334 * board data structure already normalized to platform endianness
335 * shifted to avoid unaligned access on 64 bit architecture
336 */
337 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
338 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
339 rid->port_id = pg0->PortIdentifier;
340 rid->roles = FC_RPORT_ROLE_UNKNOWN;
341 rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
342 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
343 rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
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;
354 int match = 0;
355 u64 port_name;
356 unsigned long flags;
357
358 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
359 return;
360
361 /* scan list looking for a match */
362 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
363 list_for_each_entry(ri, &ioc->fc_rports, list) {
364 port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
365 if (port_name == rport_ids.port_name) { /* match */
366 list_move_tail(&ri->list, &ioc->fc_rports);
367 match = 1;
368 break;
369 }
370 }
371 if (!match) { /* allocate one */
372 spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
373 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
374 if (!ri)
375 return;
376 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
377 list_add_tail(&ri->list, &ioc->fc_rports);
378 }
379
380 ri->pg0 = *pg0; /* add/update pg0 data */
381 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
382
383 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
384 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
385 spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
386 rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
387 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
388 if (rport) {
389 if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
390 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
391 ri->vdev = NULL;
392 ri->rport = rport;
393 *((struct mptfc_rport_info **)rport->dd_data) = ri;
394 }
395 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
396 /*
397 * if already mapped, remap here. If not mapped,
398 * slave_alloc will allocate vdev and map
399 */
400 if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
401 ri->vdev->target_id = ri->pg0.CurrentTargetID;
402 ri->vdev->bus_id = ri->pg0.CurrentBus;
403 ri->vdev->vtarget->target_id = ri->vdev->target_id;
404 ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
405 }
406 #ifdef MPT_DEBUG
407 printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
408 "rport tid %d, tmo %d\n",
409 ioc->sh->host_no,
410 pg0->PortIdentifier,
411 pg0->WWNN,
412 pg0->WWPN,
413 pg0->CurrentTargetID,
414 ri->rport->scsi_target_id,
415 ri->rport->dev_loss_tmo);
416 #endif
417 } else {
418 list_del(&ri->list);
419 kfree(ri);
420 ri = NULL;
421 }
422 }
423 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
424
425}
426
427/*
428 * OS entry point to allow host driver to alloc memory
429 * for each scsi device. Called once per device the bus scan.
430 * Return non-zero if allocation fails.
431 * Init memory once per LUN.
432 */
433int
434mptfc_slave_alloc(struct scsi_device *sdev)
435{
436 MPT_SCSI_HOST *hd;
437 VirtTarget *vtarget;
438 VirtDevice *vdev;
439 struct scsi_target *starget;
440 struct fc_rport *rport;
441 struct mptfc_rport_info *ri;
442 unsigned long flags;
443
444
445 rport = starget_to_rport(scsi_target(sdev));
446
447 if (!rport || fc_remote_port_chkready(rport))
448 return -ENXIO;
449
450 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
451
452 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
453 if (!vdev) {
454 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
455 hd->ioc->name, sizeof(VirtDevice));
456 return -ENOMEM;
457 }
458 memset(vdev, 0, sizeof(VirtDevice));
459
460 spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
461
462 if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
463 spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
464 kfree(vdev);
465 return -ENODEV;
466 }
467
468 sdev->hostdata = vdev;
469 starget = scsi_target(sdev);
470 vtarget = starget->hostdata;
471 if (vtarget->num_luns == 0) {
472 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
473 MPT_TARGET_FLAGS_VALID_INQUIRY;
474 hd->Targets[sdev->id] = vtarget;
475 }
476
477 vtarget->target_id = vdev->target_id;
478 vtarget->bus_id = vdev->bus_id;
479
480 vdev->vtarget = vtarget;
481 vdev->ioc_id = hd->ioc->id;
482 vdev->lun = sdev->lun;
483 vdev->target_id = ri->pg0.CurrentTargetID;
484 vdev->bus_id = ri->pg0.CurrentBus;
485
486 ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
487 ri->vdev = vdev;
488
489 spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
490
491 vtarget->num_luns++;
492
493#ifdef MPT_DEBUG
494 printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
495 "CurrentTargetID %d, %x %llx %llx\n",
496 sdev->host->host_no,
497 vtarget->num_luns,
498 sdev->id, ri->pg0.CurrentTargetID,
499 ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
500#endif
501
502 return 0;
503}
504
505static int
506mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
507{
508 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
509 int err;
510
511 err = fc_remote_port_chkready(rport);
512 if (unlikely(err)) {
513 SCpnt->result = err;
514 done(SCpnt);
515 return 0;
516 }
517 return mptscsih_qcmd(SCpnt,done);
518}
519
520static void
521mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
522{
523 unsigned class = 0, cos = 0;
524
525 /* don't know what to do as only one scsi (fc) host was allocated */
526 if (portnum != 0)
527 return;
528
529 class = ioc->fc_port_page0[portnum].SupportedServiceClass;
530 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
531 cos |= FC_COS_CLASS1;
532 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
533 cos |= FC_COS_CLASS2;
534 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
535 cos |= FC_COS_CLASS3;
536
537 fc_host_node_name(ioc->sh) =
538 (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
539 | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
540
541 fc_host_port_name(ioc->sh) =
542 (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
543 | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
544
545 fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
546
547 fc_host_supported_classes(ioc->sh) = cos;
548
549 fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
550}
551
552static void
553mptfc_rescan_devices(void *arg)
554{
555 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
556 int ii;
557 int work_to_do;
558 unsigned long flags;
559 struct mptfc_rport_info *ri;
560
561 do {
562 /* start by tagging all ports as missing */
563 spin_lock_irqsave(&ioc->fc_rport_lock,flags);
564 list_for_each_entry(ri, &ioc->fc_rports, list) {
565 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
566 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
567 }
568 }
569 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
570
571 /*
572 * now rescan devices known to adapter,
573 * will reregister existing rports
574 */
575 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
576 (void) mptbase_GetFcPortPage0(ioc, ii);
577 mptfc_init_host_attr(ioc,ii); /* refresh */
578 mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
579 }
580
581 /* delete devices still missing */
582 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
583 list_for_each_entry(ri, &ioc->fc_rports, list) {
584 /* if newly missing, delete it */
585 if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
586 MPT_RPORT_INFO_FLAGS_MISSING))
587 == (MPT_RPORT_INFO_FLAGS_REGISTERED |
588 MPT_RPORT_INFO_FLAGS_MISSING)) {
589
590 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
591 MPT_RPORT_INFO_FLAGS_MISSING);
592 fc_remote_port_delete(ri->rport);
593 /*
594 * remote port not really deleted 'cause
595 * binding is by WWPN and driver only
596 * registers FCP_TARGETs
597 */
598 #ifdef MPT_DEBUG
599 printk ("mptfc_rescan.%d: %llx deleted\n",
600 ioc->sh->host_no, ri->pg0.WWPN);
601 #endif
602 }
603 }
604 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
605
606 /*
607 * allow multiple passes as target state
608 * might have changed during scan
609 */
610 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
611 if (ioc->fc_rescan_work_count > 2) /* only need one more */
612 ioc->fc_rescan_work_count = 2;
613 work_to_do = --ioc->fc_rescan_work_count;
614 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
615 } while (work_to_do);
616}
617
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400618static int
619mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
620{
621 struct Scsi_Host *sh;
622 MPT_SCSI_HOST *hd;
623 MPT_ADAPTER *ioc;
624 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100625 int ii;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400626 int numSGE = 0;
627 int scale;
628 int ioc_cap;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400629 int error=0;
630 int r;
Michael Reed05e8ec12006-01-13 14:31:54 -0600631
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400632 if ((r = mpt_attach(pdev,id)) != 0)
633 return r;
Michael Reed05e8ec12006-01-13 14:31:54 -0600634
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400635 ioc = pci_get_drvdata(pdev);
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500636 ioc->DoneCtx = mptfcDoneCtx;
637 ioc->TaskCtx = mptfcTaskCtx;
638 ioc->InternalCtx = mptfcInternalCtx;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400639
640 /* Added sanity check on readiness of the MPT adapter.
641 */
642 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
643 printk(MYIOC_s_WARN_FMT
644 "Skipping because it's not operational!\n",
645 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700646 error = -ENODEV;
647 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400648 }
649
650 if (!ioc->active) {
651 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
652 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700653 error = -ENODEV;
654 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400655 }
656
657 /* Sanity check - ensure at least 1 port is INITIATOR capable
658 */
659 ioc_cap = 0;
660 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
661 if (ioc->pfacts[ii].ProtocolFlags &
662 MPI_PORTFACTS_PROTOCOL_INITIATOR)
663 ioc_cap ++;
664 }
665
666 if (!ioc_cap) {
667 printk(MYIOC_s_WARN_FMT
668 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
669 ioc->name, ioc);
Michael Reed05e8ec12006-01-13 14:31:54 -0600670 return -ENODEV;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400671 }
672
673 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
674
675 if (!sh) {
676 printk(MYIOC_s_WARN_FMT
677 "Unable to register controller with SCSI subsystem\n",
678 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700679 error = -1;
680 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400681 }
682
Michael Reed05e8ec12006-01-13 14:31:54 -0600683 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
684
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400685 spin_lock_irqsave(&ioc->FreeQlock, flags);
686
687 /* Attach the SCSI Host to the IOC structure
688 */
689 ioc->sh = sh;
690
691 sh->io_port = 0;
692 sh->n_io_port = 0;
693 sh->irq = 0;
694
695 /* set 16 byte cdb's */
696 sh->max_cmd_len = 16;
697
698 sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
699
700 sh->max_lun = MPT_LAST_LUN + 1;
701 sh->max_channel = 0;
702 sh->this_id = ioc->pfacts[0].PortSCSIID;
703
704 /* Required entry.
705 */
706 sh->unique_id = ioc->id;
707
708 /* Verify that we won't exceed the maximum
709 * number of chain buffers
710 * We can optimize: ZZ = req_sz/sizeof(SGE)
711 * For 32bit SGE's:
712 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
713 * + (req_sz - 64)/sizeof(SGE)
714 * A slightly different algorithm is required for
715 * 64bit SGEs.
716 */
717 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
718 if (sizeof(dma_addr_t) == sizeof(u64)) {
719 numSGE = (scale - 1) *
720 (ioc->facts.MaxChainDepth-1) + scale +
721 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
722 sizeof(u32));
723 } else {
724 numSGE = 1 + (scale - 1) *
725 (ioc->facts.MaxChainDepth-1) + scale +
726 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
727 sizeof(u32));
728 }
729
730 if (numSGE < sh->sg_tablesize) {
731 /* Reset this value */
732 dprintk((MYIOC_s_INFO_FMT
733 "Resetting sg_tablesize to %d from %d\n",
734 ioc->name, numSGE, sh->sg_tablesize));
735 sh->sg_tablesize = numSGE;
736 }
737
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400738 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
739
740 hd = (MPT_SCSI_HOST *) sh->hostdata;
741 hd->ioc = ioc;
742
743 /* SCSI needs scsi_cmnd lookup table!
744 * (with size equal to req_depth*PtrSz!)
745 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100746 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
747 if (!hd->ScsiLookup) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400748 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700749 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400750 }
751
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100752 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
753 ioc->name, hd->ScsiLookup));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400754
755 /* Allocate memory for the device structures.
756 * A non-Null pointer at an offset
757 * indicates a device exists.
758 * max_id = 1 + maximum id (hosts.h)
759 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100760 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
761 if (!hd->Targets) {
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400762 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700763 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400764 }
765
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +0100766 dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400767
768 /* Clear the TM flags
769 */
770 hd->tmPending = 0;
771 hd->tmState = TM_STATE_NONE;
772 hd->resetPending = 0;
773 hd->abortSCpnt = NULL;
774
775 /* Clear the pointer used to store
776 * single-threaded commands, i.e., those
777 * issued during a bus scan, dv and
778 * configuration pages.
779 */
780 hd->cmdPtr = NULL;
781
782 /* Initialize this SCSI Hosts' timers
783 * To use, set the timer expires field
784 * and add_timer
785 */
786 init_timer(&hd->timer);
787 hd->timer.data = (unsigned long) hd;
788 hd->timer.function = mptscsih_timer_expired;
789
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400790 hd->mpt_pq_filter = mpt_pq_filter;
791
792 ddvprintk((MYIOC_s_INFO_FMT
793 "mpt_pq_filter %x\n",
794 ioc->name,
795 mpt_pq_filter));
796
797 init_waitqueue_head(&hd->scandv_waitq);
798 hd->scandv_wait_done = 0;
799 hd->last_queue_full = 0;
800
Michael Reed05e8ec12006-01-13 14:31:54 -0600801 sh->transportt = mptfc_transport_template;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400802 error = scsi_add_host (sh, &ioc->pcidev->dev);
803 if(error) {
804 dprintk((KERN_ERR MYNAM
805 "scsi_add_host failed\n"));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700806 goto out_mptfc_probe;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400807 }
808
Michael Reed05e8ec12006-01-13 14:31:54 -0600809 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
810 mptfc_init_host_attr(ioc,ii);
811 mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
812 }
813
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400814 return 0;
815
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -0700816out_mptfc_probe:
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400817
818 mptscsih_remove(pdev);
819 return error;
820}
821
822static struct pci_driver mptfc_driver = {
823 .name = "mptfc",
824 .id_table = mptfc_pci_table,
825 .probe = mptfc_probe,
Michael Reed05e8ec12006-01-13 14:31:54 -0600826 .remove = __devexit_p(mptfc_remove),
Greg Kroah-Hartmand18c3db2005-06-23 17:35:56 -0700827 .shutdown = mptscsih_shutdown,
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400828#ifdef CONFIG_PM
829 .suspend = mptscsih_suspend,
830 .resume = mptscsih_resume,
831#endif
832};
833
834/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
835/**
836 * mptfc_init - Register MPT adapter(s) as SCSI host(s) with
837 * linux scsi mid-layer.
838 *
839 * Returns 0 for success, non-zero for failure.
840 */
841static int __init
842mptfc_init(void)
843{
Michael Reed05e8ec12006-01-13 14:31:54 -0600844 int error;
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400845
846 show_mptmod_ver(my_NAME, my_VERSION);
847
Michael Reed05e8ec12006-01-13 14:31:54 -0600848 /* sanity check module parameter */
849 if (mptfc_dev_loss_tmo == 0)
850 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
851
852 mptfc_transport_template =
853 fc_attach_transport(&mptfc_transport_functions);
854
855 if (!mptfc_transport_template)
856 return -ENODEV;
857
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400858 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
859 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
860 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
861
862 if (mpt_event_register(mptfcDoneCtx, mptscsih_event_process) == 0) {
863 devtprintk((KERN_INFO MYNAM
864 ": Registered for IOC event notifications\n"));
865 }
866
867 if (mpt_reset_register(mptfcDoneCtx, mptscsih_ioc_reset) == 0) {
868 dprintk((KERN_INFO MYNAM
869 ": Registered for IOC reset notifications\n"));
870 }
871
Michael Reed05e8ec12006-01-13 14:31:54 -0600872 error = pci_register_driver(&mptfc_driver);
873 if (error) {
874 fc_release_transport(mptfc_transport_template);
875 }
876
877 return error;
878}
879
880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
881/**
882 * mptfc_remove - Removed fc infrastructure for devices
883 * @pdev: Pointer to pci_dev structure
884 *
885 */
886static void __devexit mptfc_remove(struct pci_dev *pdev)
887{
888 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
889 struct mptfc_rport_info *p, *n;
890
891 fc_remove_host(ioc->sh);
892
893 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
894 list_del(&p->list);
895 kfree(p);
896 }
897
898 mptscsih_remove(pdev);
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400899}
900
901/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
903/**
904 * mptfc_exit - Unregisters MPT adapter(s)
905 *
906 */
907static void __exit
908mptfc_exit(void)
909{
910 pci_unregister_driver(&mptfc_driver);
Michael Reed05e8ec12006-01-13 14:31:54 -0600911 fc_release_transport(mptfc_transport_template);
912
Moore, Eric Dean 2496af32005-04-22 18:02:41 -0400913 mpt_reset_deregister(mptfcDoneCtx);
914 dprintk((KERN_INFO MYNAM
915 ": Deregistered for IOC reset notifications\n"));
916
917 mpt_event_deregister(mptfcDoneCtx);
918 dprintk((KERN_INFO MYNAM
919 ": Deregistered for IOC event notifications\n"));
920
921 mpt_deregister(mptfcInternalCtx);
922 mpt_deregister(mptfcTaskCtx);
923 mpt_deregister(mptfcDoneCtx);
924}
925
926module_init(mptfc_init);
927module_exit(mptfc_exit);