diff options
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
| -rw-r--r-- | drivers/message/fusion/mptfc.c | 134 |
1 files changed, 83 insertions, 51 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b343f2a68b1c..856487741ef4 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
| @@ -341,9 +341,6 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) | |||
| 341 | rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; | 341 | rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low; |
| 342 | rid->port_id = pg0->PortIdentifier; | 342 | rid->port_id = pg0->PortIdentifier; |
| 343 | rid->roles = FC_RPORT_ROLE_UNKNOWN; | 343 | rid->roles = FC_RPORT_ROLE_UNKNOWN; |
| 344 | rid->roles |= FC_RPORT_ROLE_FCP_TARGET; | ||
| 345 | if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) | ||
| 346 | rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR; | ||
| 347 | 344 | ||
| 348 | return 0; | 345 | return 0; |
| 349 | } | 346 | } |
| @@ -355,15 +352,18 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
| 355 | struct fc_rport *rport; | 352 | struct fc_rport *rport; |
| 356 | struct mptfc_rport_info *ri; | 353 | struct mptfc_rport_info *ri; |
| 357 | int new_ri = 1; | 354 | int new_ri = 1; |
| 358 | u64 pn; | 355 | u64 pn, nn; |
| 359 | unsigned long flags; | ||
| 360 | VirtTarget *vtarget; | 356 | VirtTarget *vtarget; |
| 357 | u32 roles = FC_RPORT_ROLE_UNKNOWN; | ||
| 361 | 358 | ||
| 362 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) | 359 | if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) |
| 363 | return; | 360 | return; |
| 364 | 361 | ||
| 362 | roles |= FC_RPORT_ROLE_FCP_TARGET; | ||
| 363 | if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR) | ||
| 364 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | ||
| 365 | |||
| 365 | /* scan list looking for a match */ | 366 | /* scan list looking for a match */ |
| 366 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | ||
| 367 | list_for_each_entry(ri, &ioc->fc_rports, list) { | 367 | list_for_each_entry(ri, &ioc->fc_rports, list) { |
| 368 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | 368 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; |
| 369 | if (pn == rport_ids.port_name) { /* match */ | 369 | if (pn == rport_ids.port_name) { /* match */ |
| @@ -373,11 +373,9 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
| 373 | } | 373 | } |
| 374 | } | 374 | } |
| 375 | if (new_ri) { /* allocate one */ | 375 | if (new_ri) { /* allocate one */ |
| 376 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); | ||
| 377 | ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); | 376 | ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); |
| 378 | if (!ri) | 377 | if (!ri) |
| 379 | return; | 378 | return; |
| 380 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | ||
| 381 | list_add_tail(&ri->list, &ioc->fc_rports); | 379 | list_add_tail(&ri->list, &ioc->fc_rports); |
| 382 | } | 380 | } |
| 383 | 381 | ||
| @@ -387,14 +385,11 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
| 387 | /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */ | 385 | /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */ |
| 388 | if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { | 386 | if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { |
| 389 | ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; | 387 | ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; |
| 390 | spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); | ||
| 391 | rport = fc_remote_port_add(ioc->sh, channel, &rport_ids); | 388 | rport = fc_remote_port_add(ioc->sh, channel, &rport_ids); |
| 392 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | ||
| 393 | if (rport) { | 389 | if (rport) { |
| 394 | ri->rport = rport; | 390 | ri->rport = rport; |
| 395 | if (new_ri) /* may have been reset by user */ | 391 | if (new_ri) /* may have been reset by user */ |
| 396 | rport->dev_loss_tmo = mptfc_dev_loss_tmo; | 392 | rport->dev_loss_tmo = mptfc_dev_loss_tmo; |
| 397 | *((struct mptfc_rport_info **)rport->dd_data) = ri; | ||
| 398 | /* | 393 | /* |
| 399 | * if already mapped, remap here. If not mapped, | 394 | * if already mapped, remap here. If not mapped, |
| 400 | * target_alloc will allocate vtarget and map, | 395 | * target_alloc will allocate vtarget and map, |
| @@ -406,16 +401,21 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
| 406 | vtarget->target_id = pg0->CurrentTargetID; | 401 | vtarget->target_id = pg0->CurrentTargetID; |
| 407 | vtarget->bus_id = pg0->CurrentBus; | 402 | vtarget->bus_id = pg0->CurrentBus; |
| 408 | } | 403 | } |
| 409 | ri->remap_needed = 0; | ||
| 410 | } | 404 | } |
| 405 | *((struct mptfc_rport_info **)rport->dd_data) = ri; | ||
| 406 | /* scan will be scheduled once rport becomes a target */ | ||
| 407 | fc_remote_port_rolechg(rport,roles); | ||
| 408 | |||
| 409 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | ||
| 410 | nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; | ||
| 411 | dfcprintk ((MYIOC_s_INFO_FMT | 411 | dfcprintk ((MYIOC_s_INFO_FMT |
| 412 | "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " | 412 | "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " |
| 413 | "rport tid %d, tmo %d\n", | 413 | "rport tid %d, tmo %d\n", |
| 414 | ioc->name, | 414 | ioc->name, |
| 415 | ioc->sh->host_no, | 415 | ioc->sh->host_no, |
| 416 | pg0->PortIdentifier, | 416 | pg0->PortIdentifier, |
| 417 | pg0->WWNN, | 417 | (unsigned long long)nn, |
| 418 | pg0->WWPN, | 418 | (unsigned long long)pn, |
| 419 | pg0->CurrentTargetID, | 419 | pg0->CurrentTargetID, |
| 420 | ri->rport->scsi_target_id, | 420 | ri->rport->scsi_target_id, |
| 421 | ri->rport->dev_loss_tmo)); | 421 | ri->rport->dev_loss_tmo)); |
| @@ -425,8 +425,6 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
| 425 | ri = NULL; | 425 | ri = NULL; |
| 426 | } | 426 | } |
| 427 | } | 427 | } |
| 428 | spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); | ||
| 429 | |||
| 430 | } | 428 | } |
| 431 | 429 | ||
| 432 | /* | 430 | /* |
| @@ -476,7 +474,6 @@ mptfc_target_alloc(struct scsi_target *starget) | |||
| 476 | vtarget->target_id = ri->pg0.CurrentTargetID; | 474 | vtarget->target_id = ri->pg0.CurrentTargetID; |
| 477 | vtarget->bus_id = ri->pg0.CurrentBus; | 475 | vtarget->bus_id = ri->pg0.CurrentBus; |
| 478 | ri->starget = starget; | 476 | ri->starget = starget; |
| 479 | ri->remap_needed = 0; | ||
| 480 | rc = 0; | 477 | rc = 0; |
| 481 | } | 478 | } |
| 482 | } | 479 | } |
| @@ -502,10 +499,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
| 502 | VirtDevice *vdev; | 499 | VirtDevice *vdev; |
| 503 | struct scsi_target *starget; | 500 | struct scsi_target *starget; |
| 504 | struct fc_rport *rport; | 501 | struct fc_rport *rport; |
| 505 | unsigned long flags; | ||
| 506 | 502 | ||
| 507 | 503 | ||
| 508 | rport = starget_to_rport(scsi_target(sdev)); | 504 | starget = scsi_target(sdev); |
| 505 | rport = starget_to_rport(starget); | ||
| 509 | 506 | ||
| 510 | if (!rport || fc_remote_port_chkready(rport)) | 507 | if (!rport || fc_remote_port_chkready(rport)) |
| 511 | return -ENXIO; | 508 | return -ENXIO; |
| @@ -519,10 +516,8 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
| 519 | return -ENOMEM; | 516 | return -ENOMEM; |
| 520 | } | 517 | } |
| 521 | 518 | ||
| 522 | spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); | ||
| 523 | 519 | ||
| 524 | sdev->hostdata = vdev; | 520 | sdev->hostdata = vdev; |
| 525 | starget = scsi_target(sdev); | ||
| 526 | vtarget = starget->hostdata; | 521 | vtarget = starget->hostdata; |
| 527 | 522 | ||
| 528 | if (vtarget->num_luns == 0) { | 523 | if (vtarget->num_luns == 0) { |
| @@ -535,14 +530,16 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
| 535 | vdev->vtarget = vtarget; | 530 | vdev->vtarget = vtarget; |
| 536 | vdev->lun = sdev->lun; | 531 | vdev->lun = sdev->lun; |
| 537 | 532 | ||
| 538 | spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); | ||
| 539 | |||
| 540 | vtarget->num_luns++; | 533 | vtarget->num_luns++; |
| 541 | 534 | ||
| 535 | |||
| 542 | #ifdef DMPT_DEBUG_FC | 536 | #ifdef DMPT_DEBUG_FC |
| 543 | { | 537 | { |
| 538 | u64 nn, pn; | ||
| 544 | struct mptfc_rport_info *ri; | 539 | struct mptfc_rport_info *ri; |
| 545 | ri = *((struct mptfc_rport_info **)rport->dd_data); | 540 | ri = *((struct mptfc_rport_info **)rport->dd_data); |
| 541 | pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; | ||
| 542 | nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low; | ||
| 546 | dfcprintk ((MYIOC_s_INFO_FMT | 543 | dfcprintk ((MYIOC_s_INFO_FMT |
| 547 | "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " | 544 | "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " |
| 548 | "CurrentTargetID %d, %x %llx %llx\n", | 545 | "CurrentTargetID %d, %x %llx %llx\n", |
| @@ -550,7 +547,9 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
| 550 | sdev->host->host_no, | 547 | sdev->host->host_no, |
| 551 | vtarget->num_luns, | 548 | vtarget->num_luns, |
| 552 | sdev->id, ri->pg0.CurrentTargetID, | 549 | sdev->id, ri->pg0.CurrentTargetID, |
| 553 | ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN)); | 550 | ri->pg0.PortIdentifier, |
| 551 | (unsigned long long)pn, | ||
| 552 | (unsigned long long)nn)); | ||
| 554 | } | 553 | } |
| 555 | #endif | 554 | #endif |
| 556 | 555 | ||
| @@ -570,11 +569,31 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
| 570 | done(SCpnt); | 569 | done(SCpnt); |
| 571 | return 0; | 570 | return 0; |
| 572 | } | 571 | } |
| 572 | |||
| 573 | /* dd_data is null until finished adding target */ | ||
| 573 | ri = *((struct mptfc_rport_info **)rport->dd_data); | 574 | ri = *((struct mptfc_rport_info **)rport->dd_data); |
| 574 | if (unlikely(ri->remap_needed)) | 575 | if (unlikely(!ri)) { |
| 575 | return SCSI_MLQUEUE_HOST_BUSY; | 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 | } | ||
| 576 | 585 | ||
| 577 | return mptscsih_qcmd(SCpnt,done); | 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; | ||
| 578 | } | 597 | } |
| 579 | 598 | ||
| 580 | static void | 599 | static void |
| @@ -615,18 +634,17 @@ mptfc_rescan_devices(void *arg) | |||
| 615 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | 634 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; |
| 616 | int ii; | 635 | int ii; |
| 617 | int work_to_do; | 636 | int work_to_do; |
| 637 | u64 pn; | ||
| 618 | unsigned long flags; | 638 | unsigned long flags; |
| 619 | struct mptfc_rport_info *ri; | 639 | struct mptfc_rport_info *ri; |
| 620 | 640 | ||
| 621 | do { | 641 | do { |
| 622 | /* start by tagging all ports as missing */ | 642 | /* start by tagging all ports as missing */ |
| 623 | spin_lock_irqsave(&ioc->fc_rport_lock,flags); | ||
| 624 | list_for_each_entry(ri, &ioc->fc_rports, list) { | 643 | list_for_each_entry(ri, &ioc->fc_rports, list) { |
| 625 | if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { | 644 | if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { |
| 626 | ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; | 645 | ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; |
| 627 | } | 646 | } |
| 628 | } | 647 | } |
| 629 | spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); | ||
| 630 | 648 | ||
| 631 | /* | 649 | /* |
| 632 | * now rescan devices known to adapter, | 650 | * now rescan devices known to adapter, |
| @@ -639,33 +657,24 @@ mptfc_rescan_devices(void *arg) | |||
| 639 | } | 657 | } |
| 640 | 658 | ||
| 641 | /* delete devices still missing */ | 659 | /* delete devices still missing */ |
| 642 | spin_lock_irqsave(&ioc->fc_rport_lock, flags); | ||
| 643 | list_for_each_entry(ri, &ioc->fc_rports, list) { | 660 | list_for_each_entry(ri, &ioc->fc_rports, list) { |
| 644 | /* if newly missing, delete it */ | 661 | /* if newly missing, delete it */ |
| 645 | if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED | | 662 | if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { |
| 646 | MPT_RPORT_INFO_FLAGS_MISSING)) | ||
| 647 | == (MPT_RPORT_INFO_FLAGS_REGISTERED | | ||
| 648 | MPT_RPORT_INFO_FLAGS_MISSING)) { | ||
| 649 | 663 | ||
| 650 | ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| | 664 | ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| |
| 651 | MPT_RPORT_INFO_FLAGS_MISSING); | 665 | MPT_RPORT_INFO_FLAGS_MISSING); |
| 652 | ri->remap_needed = 1; | 666 | fc_remote_port_delete(ri->rport); /* won't sleep */ |
| 653 | fc_remote_port_delete(ri->rport); | ||
| 654 | /* | ||
| 655 | * remote port not really deleted 'cause | ||
| 656 | * binding is by WWPN and driver only | ||
| 657 | * registers FCP_TARGETs but cannot trust | ||
| 658 | * data structures. | ||
| 659 | */ | ||
| 660 | ri->rport = NULL; | 667 | ri->rport = NULL; |
| 668 | |||
| 669 | pn = (u64)ri->pg0.WWPN.High << 32 | | ||
| 670 | (u64)ri->pg0.WWPN.Low; | ||
| 661 | dfcprintk ((MYIOC_s_INFO_FMT | 671 | dfcprintk ((MYIOC_s_INFO_FMT |
| 662 | "mptfc_rescan.%d: %llx deleted\n", | 672 | "mptfc_rescan.%d: %llx deleted\n", |
| 663 | ioc->name, | 673 | ioc->name, |
| 664 | ioc->sh->host_no, | 674 | ioc->sh->host_no, |
| 665 | ri->pg0.WWPN)); | 675 | (unsigned long long)pn)); |
| 666 | } | 676 | } |
| 667 | } | 677 | } |
| 668 | spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); | ||
| 669 | 678 | ||
| 670 | /* | 679 | /* |
| 671 | * allow multiple passes as target state | 680 | * allow multiple passes as target state |
| @@ -870,10 +879,23 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 870 | goto out_mptfc_probe; | 879 | goto out_mptfc_probe; |
| 871 | } | 880 | } |
| 872 | 881 | ||
| 873 | for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { | 882 | /* initialize workqueue */ |
| 874 | mptfc_init_host_attr(ioc,ii); | 883 | |
| 875 | mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); | 884 | snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d", |
| 876 | } | 885 | sh->host_no); |
| 886 | ioc->fc_rescan_work_q = | ||
| 887 | create_singlethread_workqueue(ioc->fc_rescan_work_q_name); | ||
| 888 | if (!ioc->fc_rescan_work_q) | ||
| 889 | goto out_mptfc_probe; | ||
| 890 | |||
| 891 | /* | ||
| 892 | * scan for rports - | ||
| 893 | * by doing it via the workqueue, some locking is eliminated | ||
| 894 | */ | ||
| 895 | |||
| 896 | ioc->fc_rescan_work_count = 1; | ||
| 897 | queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); | ||
| 898 | flush_workqueue(ioc->fc_rescan_work_q); | ||
| 877 | 899 | ||
| 878 | return 0; | 900 | return 0; |
| 879 | 901 | ||
| @@ -949,8 +971,18 @@ mptfc_init(void) | |||
| 949 | static void __devexit | 971 | static void __devexit |
| 950 | mptfc_remove(struct pci_dev *pdev) | 972 | mptfc_remove(struct pci_dev *pdev) |
| 951 | { | 973 | { |
| 952 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 974 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
| 953 | struct mptfc_rport_info *p, *n; | 975 | struct mptfc_rport_info *p, *n; |
| 976 | struct workqueue_struct *work_q; | ||
| 977 | unsigned long flags; | ||
| 978 | |||
| 979 | /* destroy workqueue */ | ||
| 980 | if ((work_q=ioc->fc_rescan_work_q)) { | ||
| 981 | spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); | ||
| 982 | ioc->fc_rescan_work_q = NULL; | ||
| 983 | spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); | ||
| 984 | destroy_workqueue(work_q); | ||
| 985 | } | ||
| 954 | 986 | ||
| 955 | fc_remove_host(ioc->sh); | 987 | fc_remove_host(ioc->sh); |
| 956 | 988 | ||
