aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/message/fusion/mptfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
-rw-r--r--drivers/message/fusion/mptfc.c579
1 files changed, 545 insertions, 34 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index ba61e1828858..b102c7666d0e 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -55,12 +55,14 @@
55#include <linux/reboot.h> /* notifier code */ 55#include <linux/reboot.h> /* notifier code */
56#include <linux/sched.h> 56#include <linux/sched.h>
57#include <linux/workqueue.h> 57#include <linux/workqueue.h>
58#include <linux/sort.h>
58 59
59#include <scsi/scsi.h> 60#include <scsi/scsi.h>
60#include <scsi/scsi_cmnd.h> 61#include <scsi/scsi_cmnd.h>
61#include <scsi/scsi_device.h> 62#include <scsi/scsi_device.h>
62#include <scsi/scsi_host.h> 63#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h> 64#include <scsi/scsi_tcq.h>
65#include <scsi/scsi_transport_fc.h>
64 66
65#include "mptbase.h" 67#include "mptbase.h"
66#include "mptscsih.h" 68#include "mptscsih.h"
@@ -79,19 +81,34 @@ static int mpt_pq_filter = 0;
79module_param(mpt_pq_filter, int, 0); 81module_param(mpt_pq_filter, int, 0);
80MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)"); 82MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
81 83
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
82static int mptfcDoneCtx = -1; 92static int mptfcDoneCtx = -1;
83static int mptfcTaskCtx = -1; 93static int mptfcTaskCtx = -1;
84static int mptfcInternalCtx = -1; /* Used only for internal commands */ 94static int mptfcInternalCtx = -1; /* Used only for internal commands */
85 95
96int 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
86static struct scsi_host_template mptfc_driver_template = { 103static struct scsi_host_template mptfc_driver_template = {
87 .module = THIS_MODULE, 104 .module = THIS_MODULE,
88 .proc_name = "mptfc", 105 .proc_name = "mptfc",
89 .proc_info = mptscsih_proc_info, 106 .proc_info = mptscsih_proc_info,
90 .name = "MPT FC Host", 107 .name = "MPT FC Host",
91 .info = mptscsih_info, 108 .info = mptscsih_info,
92 .queuecommand = mptscsih_qcmd, 109 .queuecommand = mptfc_qcmd,
93 .target_alloc = mptscsih_target_alloc, 110 .target_alloc = mptscsih_target_alloc,
94 .slave_alloc = mptscsih_slave_alloc, 111 .slave_alloc = mptfc_slave_alloc,
95 .slave_configure = mptscsih_slave_configure, 112 .slave_configure = mptscsih_slave_configure,
96 .target_destroy = mptscsih_target_destroy, 113 .target_destroy = mptscsih_target_destroy,
97 .slave_destroy = mptscsih_slave_destroy, 114 .slave_destroy = mptscsih_slave_destroy,
@@ -128,19 +145,478 @@ static struct pci_device_id mptfc_pci_table[] = {
128 PCI_ANY_ID, PCI_ANY_ID }, 145 PCI_ANY_ID, PCI_ANY_ID },
129 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X, 146 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
130 PCI_ANY_ID, PCI_ANY_ID }, 147 PCI_ANY_ID, PCI_ANY_ID },
148 { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
149 PCI_ANY_ID, PCI_ANY_ID },
131 {0} /* Terminating entry */ 150 {0} /* Terminating entry */
132}; 151};
133MODULE_DEVICE_TABLE(pci, mptfc_pci_table); 152MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
134 153
135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 154static struct scsi_transport_template *mptfc_transport_template = NULL;
136/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 155
156struct fc_function_template mptfc_transport_functions = {
157 .dd_fcrport_size = 8,
158 .show_host_node_name = 1,
159 .show_host_port_name = 1,
160 .show_host_supported_classes = 1,
161 .show_host_port_id = 1,
162 .show_rport_supported_classes = 1,
163 .show_starget_node_name = 1,
164 .show_starget_port_name = 1,
165 .show_starget_port_id = 1,
166 .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
167 .show_rport_dev_loss_tmo = 1,
168
169};
170
171/* FIXME! values controlling firmware RESCAN event
172 * need to be set low to allow dev_loss_tmo to
173 * work as expected. Currently, firmware doesn't
174 * notify driver of RESCAN event until some number
175 * of seconds elapse. This value can be set via
176 * lsiutil.
177 */
178static void
179mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
180{
181 if (timeout > 0)
182 rport->dev_loss_tmo = timeout;
183 else
184 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
185}
186
187static int
188mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
189{
190 FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
191 FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
192
193 if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
194 if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
195 return 0;
196 if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
197 return -1;
198 return 1;
199 }
200 if ((*aa)->CurrentBus < (*bb)->CurrentBus)
201 return -1;
202 return 1;
203}
204
205static int
206mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
207 void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
208{
209 ConfigPageHeader_t hdr;
210 CONFIGPARMS cfg;
211 FCDevicePage0_t *ppage0_alloc, *fc;
212 dma_addr_t page0_dma;
213 int data_sz;
214 int ii;
215
216 FCDevicePage0_t *p0_array=NULL, *p_p0;
217 FCDevicePage0_t **pp0_array=NULL, **p_pp0;
218
219 int rc = -ENOMEM;
220 U32 port_id = 0xffffff;
221 int num_targ = 0;
222 int max_bus = ioc->facts.MaxBuses;
223 int max_targ = ioc->facts.MaxDevices;
224
225 if (max_bus == 0 || max_targ == 0)
226 goto out;
227
228 data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
229 p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
230 if (!p0_array)
231 goto out;
232
233 data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
234 p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
235 if (!pp0_array)
236 goto out;
237
238 do {
239 /* Get FC Device Page 0 header */
240 hdr.PageVersion = 0;
241 hdr.PageLength = 0;
242 hdr.PageNumber = 0;
243 hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
244 cfg.cfghdr.hdr = &hdr;
245 cfg.physAddr = -1;
246 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
247 cfg.dir = 0;
248 cfg.pageAddr = port_id;
249 cfg.timeout = 0;
250
251 if ((rc = mpt_config(ioc, &cfg)) != 0)
252 break;
253
254 if (hdr.PageLength <= 0)
255 break;
256
257 data_sz = hdr.PageLength * 4;
258 ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
259 &page0_dma);
260 rc = -ENOMEM;
261 if (!ppage0_alloc)
262 break;
263
264 cfg.physAddr = page0_dma;
265 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
266
267 if ((rc = mpt_config(ioc, &cfg)) == 0) {
268 ppage0_alloc->PortIdentifier =
269 le32_to_cpu(ppage0_alloc->PortIdentifier);
270
271 ppage0_alloc->WWNN.Low =
272 le32_to_cpu(ppage0_alloc->WWNN.Low);
273
274 ppage0_alloc->WWNN.High =
275 le32_to_cpu(ppage0_alloc->WWNN.High);
276
277 ppage0_alloc->WWPN.Low =
278 le32_to_cpu(ppage0_alloc->WWPN.Low);
279
280 ppage0_alloc->WWPN.High =
281 le32_to_cpu(ppage0_alloc->WWPN.High);
282
283 ppage0_alloc->BBCredit =
284 le16_to_cpu(ppage0_alloc->BBCredit);
285
286 ppage0_alloc->MaxRxFrameSize =
287 le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
288
289 port_id = ppage0_alloc->PortIdentifier;
290 num_targ++;
291 *p_p0 = *ppage0_alloc; /* save data */
292 *p_pp0++ = p_p0++; /* save addr */
293 }
294 pci_free_consistent(ioc->pcidev, data_sz,
295 (u8 *) ppage0_alloc, page0_dma);
296 if (rc != 0)
297 break;
298
299 } while (port_id <= 0xff0000);
300
301 if (num_targ) {
302 /* sort array */
303 if (num_targ > 1)
304 sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
305 mptfc_FcDevPage0_cmp_func, NULL);
306 /* call caller's func for each targ */
307 for (ii = 0; ii < num_targ; ii++) {
308 fc = *(pp0_array+ii);
309 func(ioc, ioc_port, fc);
310 }
311 }
312
313 out:
314 if (pp0_array)
315 kfree(pp0_array);
316 if (p0_array)
317 kfree(p0_array);
318 return rc;
319}
320
321static int
322mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
323{
324 /* not currently usable */
325 if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
326 MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
327 return -1;
328
329 if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
330 return -1;
331
332 if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
333 return -1;
334
335 /*
336 * board data structure already normalized to platform endianness
337 * shifted to avoid unaligned access on 64 bit architecture
338 */
339 rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
340 rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
341 rid->port_id = pg0->PortIdentifier;
342 rid->roles = FC_RPORT_ROLE_UNKNOWN;
343 rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
344 if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
345 rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
346
347 return 0;
348}
349
350static void
351mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
352{
353 struct fc_rport_identifiers rport_ids;
354 struct fc_rport *rport;
355 struct mptfc_rport_info *ri;
356 int match = 0;
357 u64 port_name;
358 unsigned long flags;
359
360 if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
361 return;
362
363 /* scan list looking for a match */
364 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
365 list_for_each_entry(ri, &ioc->fc_rports, list) {
366 port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
367 if (port_name == rport_ids.port_name) { /* match */
368 list_move_tail(&ri->list, &ioc->fc_rports);
369 match = 1;
370 break;
371 }
372 }
373 if (!match) { /* allocate one */
374 spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
375 ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
376 if (!ri)
377 return;
378 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
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 if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
386 ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
387 spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
388 rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
389 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
390 if (rport) {
391 if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
392 ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
393 ri->vdev = NULL;
394 ri->rport = rport;
395 *((struct mptfc_rport_info **)rport->dd_data) = ri;
396 }
397 rport->dev_loss_tmo = mptfc_dev_loss_tmo;
398 /*
399 * if already mapped, remap here. If not mapped,
400 * slave_alloc will allocate vdev and map
401 */
402 if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
403 ri->vdev->target_id = ri->pg0.CurrentTargetID;
404 ri->vdev->bus_id = ri->pg0.CurrentBus;
405 ri->vdev->vtarget->target_id = ri->vdev->target_id;
406 ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
407 }
408 #ifdef MPT_DEBUG
409 printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
410 "rport tid %d, tmo %d\n",
411 ioc->sh->host_no,
412 pg0->PortIdentifier,
413 pg0->WWNN,
414 pg0->WWPN,
415 pg0->CurrentTargetID,
416 ri->rport->scsi_target_id,
417 ri->rport->dev_loss_tmo);
418 #endif
419 } else {
420 list_del(&ri->list);
421 kfree(ri);
422 ri = NULL;
423 }
424 }
425 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
426
427}
428
137/* 429/*
138 * mptfc_probe - Installs scsi devices per bus. 430 * OS entry point to allow host driver to alloc memory
139 * @pdev: Pointer to pci_dev structure 431 * for each scsi device. Called once per device the bus scan.
140 * 432 * Return non-zero if allocation fails.
141 * Returns 0 for success, non-zero for failure. 433 * Init memory once per LUN.
142 *
143 */ 434 */
435int
436mptfc_slave_alloc(struct scsi_device *sdev)
437{
438 MPT_SCSI_HOST *hd;
439 VirtTarget *vtarget;
440 VirtDevice *vdev;
441 struct scsi_target *starget;
442 struct fc_rport *rport;
443 struct mptfc_rport_info *ri;
444 unsigned long flags;
445
446
447 rport = starget_to_rport(scsi_target(sdev));
448
449 if (!rport || fc_remote_port_chkready(rport))
450 return -ENXIO;
451
452 hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
453
454 vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
455 if (!vdev) {
456 printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
457 hd->ioc->name, sizeof(VirtDevice));
458 return -ENOMEM;
459 }
460 memset(vdev, 0, sizeof(VirtDevice));
461
462 spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
463
464 if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
465 spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
466 kfree(vdev);
467 return -ENODEV;
468 }
469
470 sdev->hostdata = vdev;
471 starget = scsi_target(sdev);
472 vtarget = starget->hostdata;
473 if (vtarget->num_luns == 0) {
474 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
475 MPT_TARGET_FLAGS_VALID_INQUIRY;
476 hd->Targets[sdev->id] = vtarget;
477 }
478
479 vtarget->target_id = vdev->target_id;
480 vtarget->bus_id = vdev->bus_id;
481
482 vdev->vtarget = vtarget;
483 vdev->ioc_id = hd->ioc->id;
484 vdev->lun = sdev->lun;
485 vdev->target_id = ri->pg0.CurrentTargetID;
486 vdev->bus_id = ri->pg0.CurrentBus;
487
488 ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
489 ri->vdev = vdev;
490
491 spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
492
493 vtarget->num_luns++;
494
495#ifdef MPT_DEBUG
496 printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
497 "CurrentTargetID %d, %x %llx %llx\n",
498 sdev->host->host_no,
499 vtarget->num_luns,
500 sdev->id, ri->pg0.CurrentTargetID,
501 ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
502#endif
503
504 return 0;
505}
506
507static int
508mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
509{
510 struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
511 int err;
512
513 err = fc_remote_port_chkready(rport);
514 if (unlikely(err)) {
515 SCpnt->result = err;
516 done(SCpnt);
517 return 0;
518 }
519 return mptscsih_qcmd(SCpnt,done);
520}
521
522static void
523mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
524{
525 unsigned class = 0, cos = 0;
526
527 /* don't know what to do as only one scsi (fc) host was allocated */
528 if (portnum != 0)
529 return;
530
531 class = ioc->fc_port_page0[portnum].SupportedServiceClass;
532 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
533 cos |= FC_COS_CLASS1;
534 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
535 cos |= FC_COS_CLASS2;
536 if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
537 cos |= FC_COS_CLASS3;
538
539 fc_host_node_name(ioc->sh) =
540 (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
541 | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
542
543 fc_host_port_name(ioc->sh) =
544 (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
545 | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
546
547 fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
548
549 fc_host_supported_classes(ioc->sh) = cos;
550
551 fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
552}
553
554static void
555mptfc_rescan_devices(void *arg)
556{
557 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
558 int ii;
559 int work_to_do;
560 unsigned long flags;
561 struct mptfc_rport_info *ri;
562
563 do {
564 /* start by tagging all ports as missing */
565 spin_lock_irqsave(&ioc->fc_rport_lock,flags);
566 list_for_each_entry(ri, &ioc->fc_rports, list) {
567 if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
568 ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
569 }
570 }
571 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
572
573 /*
574 * now rescan devices known to adapter,
575 * will reregister existing rports
576 */
577 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
578 (void) mptbase_GetFcPortPage0(ioc, ii);
579 mptfc_init_host_attr(ioc,ii); /* refresh */
580 mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
581 }
582
583 /* delete devices still missing */
584 spin_lock_irqsave(&ioc->fc_rport_lock, flags);
585 list_for_each_entry(ri, &ioc->fc_rports, list) {
586 /* if newly missing, delete it */
587 if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
588 MPT_RPORT_INFO_FLAGS_MISSING))
589 == (MPT_RPORT_INFO_FLAGS_REGISTERED |
590 MPT_RPORT_INFO_FLAGS_MISSING)) {
591
592 ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
593 MPT_RPORT_INFO_FLAGS_MISSING);
594 fc_remote_port_delete(ri->rport);
595 /*
596 * remote port not really deleted 'cause
597 * binding is by WWPN and driver only
598 * registers FCP_TARGETs
599 */
600 #ifdef MPT_DEBUG
601 printk ("mptfc_rescan.%d: %llx deleted\n",
602 ioc->sh->host_no, ri->pg0.WWPN);
603 #endif
604 }
605 }
606 spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
607
608 /*
609 * allow multiple passes as target state
610 * might have changed during scan
611 */
612 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
613 if (ioc->fc_rescan_work_count > 2) /* only need one more */
614 ioc->fc_rescan_work_count = 2;
615 work_to_do = --ioc->fc_rescan_work_count;
616 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
617 } while (work_to_do);
618}
619
144static int 620static int
145mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) 621mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
146{ 622{
@@ -148,17 +624,16 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
148 MPT_SCSI_HOST *hd; 624 MPT_SCSI_HOST *hd;
149 MPT_ADAPTER *ioc; 625 MPT_ADAPTER *ioc;
150 unsigned long flags; 626 unsigned long flags;
151 int sz, ii; 627 int ii;
152 int numSGE = 0; 628 int numSGE = 0;
153 int scale; 629 int scale;
154 int ioc_cap; 630 int ioc_cap;
155 u8 *mem;
156 int error=0; 631 int error=0;
157 int r; 632 int r;
158 633
159 if ((r = mpt_attach(pdev,id)) != 0) 634 if ((r = mpt_attach(pdev,id)) != 0)
160 return r; 635 return r;
161 636
162 ioc = pci_get_drvdata(pdev); 637 ioc = pci_get_drvdata(pdev);
163 ioc->DoneCtx = mptfcDoneCtx; 638 ioc->DoneCtx = mptfcDoneCtx;
164 ioc->TaskCtx = mptfcTaskCtx; 639 ioc->TaskCtx = mptfcTaskCtx;
@@ -194,7 +669,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
194 printk(MYIOC_s_WARN_FMT 669 printk(MYIOC_s_WARN_FMT
195 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", 670 "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
196 ioc->name, ioc); 671 ioc->name, ioc);
197 return 0; 672 return -ENODEV;
198 } 673 }
199 674
200 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST)); 675 sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -207,6 +682,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
207 goto out_mptfc_probe; 682 goto out_mptfc_probe;
208 } 683 }
209 684
685 INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
686
210 spin_lock_irqsave(&ioc->FreeQlock, flags); 687 spin_lock_irqsave(&ioc->FreeQlock, flags);
211 688
212 /* Attach the SCSI Host to the IOC structure 689 /* Attach the SCSI Host to the IOC structure
@@ -268,36 +745,27 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
268 /* SCSI needs scsi_cmnd lookup table! 745 /* SCSI needs scsi_cmnd lookup table!
269 * (with size equal to req_depth*PtrSz!) 746 * (with size equal to req_depth*PtrSz!)
270 */ 747 */
271 sz = ioc->req_depth * sizeof(void *); 748 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
272 mem = kmalloc(sz, GFP_ATOMIC); 749 if (!hd->ScsiLookup) {
273 if (mem == NULL) {
274 error = -ENOMEM; 750 error = -ENOMEM;
275 goto out_mptfc_probe; 751 goto out_mptfc_probe;
276 } 752 }
277 753
278 memset(mem, 0, sz); 754 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
279 hd->ScsiLookup = (struct scsi_cmnd **) mem; 755 ioc->name, hd->ScsiLookup));
280
281 dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
282 ioc->name, hd->ScsiLookup, sz));
283 756
284 /* Allocate memory for the device structures. 757 /* Allocate memory for the device structures.
285 * A non-Null pointer at an offset 758 * A non-Null pointer at an offset
286 * indicates a device exists. 759 * indicates a device exists.
287 * max_id = 1 + maximum id (hosts.h) 760 * max_id = 1 + maximum id (hosts.h)
288 */ 761 */
289 sz = sh->max_id * sizeof(void *); 762 hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
290 mem = kmalloc(sz, GFP_ATOMIC); 763 if (!hd->Targets) {
291 if (mem == NULL) {
292 error = -ENOMEM; 764 error = -ENOMEM;
293 goto out_mptfc_probe; 765 goto out_mptfc_probe;
294 } 766 }
295 767
296 memset(mem, 0, sz); 768 dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
297 hd->Targets = (VirtTarget **) mem;
298
299 dprintk((KERN_INFO
300 " vdev @ %p, sz=%d\n", hd->Targets, sz));
301 769
302 /* Clear the TM flags 770 /* Clear the TM flags
303 */ 771 */
@@ -332,6 +800,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
332 hd->scandv_wait_done = 0; 800 hd->scandv_wait_done = 0;
333 hd->last_queue_full = 0; 801 hd->last_queue_full = 0;
334 802
803 sh->transportt = mptfc_transport_template;
335 error = scsi_add_host (sh, &ioc->pcidev->dev); 804 error = scsi_add_host (sh, &ioc->pcidev->dev);
336 if(error) { 805 if(error) {
337 dprintk((KERN_ERR MYNAM 806 dprintk((KERN_ERR MYNAM
@@ -339,7 +808,11 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
339 goto out_mptfc_probe; 808 goto out_mptfc_probe;
340 } 809 }
341 810
342 scsi_scan_host(sh); 811 for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
812 mptfc_init_host_attr(ioc,ii);
813 mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
814 }
815
343 return 0; 816 return 0;
344 817
345out_mptfc_probe: 818out_mptfc_probe:
@@ -352,7 +825,7 @@ static struct pci_driver mptfc_driver = {
352 .name = "mptfc", 825 .name = "mptfc",
353 .id_table = mptfc_pci_table, 826 .id_table = mptfc_pci_table,
354 .probe = mptfc_probe, 827 .probe = mptfc_probe,
355 .remove = __devexit_p(mptscsih_remove), 828 .remove = __devexit_p(mptfc_remove),
356 .shutdown = mptscsih_shutdown, 829 .shutdown = mptscsih_shutdown,
357#ifdef CONFIG_PM 830#ifdef CONFIG_PM
358 .suspend = mptscsih_suspend, 831 .suspend = mptscsih_suspend,
@@ -370,9 +843,20 @@ static struct pci_driver mptfc_driver = {
370static int __init 843static int __init
371mptfc_init(void) 844mptfc_init(void)
372{ 845{
846 int error;
373 847
374 show_mptmod_ver(my_NAME, my_VERSION); 848 show_mptmod_ver(my_NAME, my_VERSION);
375 849
850 /* sanity check module parameter */
851 if (mptfc_dev_loss_tmo == 0)
852 mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
853
854 mptfc_transport_template =
855 fc_attach_transport(&mptfc_transport_functions);
856
857 if (!mptfc_transport_template)
858 return -ENODEV;
859
376 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER); 860 mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
377 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER); 861 mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
378 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER); 862 mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -387,7 +871,33 @@ mptfc_init(void)
387 ": Registered for IOC reset notifications\n")); 871 ": Registered for IOC reset notifications\n"));
388 } 872 }
389 873
390 return pci_register_driver(&mptfc_driver); 874 error = pci_register_driver(&mptfc_driver);
875 if (error) {
876 fc_release_transport(mptfc_transport_template);
877 }
878
879 return error;
880}
881
882/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
883/**
884 * mptfc_remove - Removed fc infrastructure for devices
885 * @pdev: Pointer to pci_dev structure
886 *
887 */
888static void __devexit mptfc_remove(struct pci_dev *pdev)
889{
890 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
891 struct mptfc_rport_info *p, *n;
892
893 fc_remove_host(ioc->sh);
894
895 list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
896 list_del(&p->list);
897 kfree(p);
898 }
899
900 mptscsih_remove(pdev);
391} 901}
392 902
393/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 903/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -400,7 +910,8 @@ static void __exit
400mptfc_exit(void) 910mptfc_exit(void)
401{ 911{
402 pci_unregister_driver(&mptfc_driver); 912 pci_unregister_driver(&mptfc_driver);
403 913 fc_release_transport(mptfc_transport_template);
914
404 mpt_reset_deregister(mptfcDoneCtx); 915 mpt_reset_deregister(mptfcDoneCtx);
405 dprintk((KERN_INFO MYNAM 916 dprintk((KERN_INFO MYNAM
406 ": Deregistered for IOC reset notifications\n")); 917 ": Deregistered for IOC reset notifications\n"));