diff options
Diffstat (limited to 'drivers/scsi/fnic/fnic_main.c')
-rw-r--r-- | drivers/scsi/fnic/fnic_main.c | 109 |
1 files changed, 63 insertions, 46 deletions
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 71c7bbe26d05..97b212570bcc 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/mempool.h> | 19 | #include <linux/mempool.h> |
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/slab.h> | ||
21 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
22 | #include <linux/init.h> | 23 | #include <linux/init.h> |
23 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
@@ -25,6 +26,8 @@ | |||
25 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
26 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
27 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/if_ether.h> | ||
30 | #include <scsi/fc/fc_fip.h> | ||
28 | #include <scsi/scsi_host.h> | 31 | #include <scsi/scsi_host.h> |
29 | #include <scsi/scsi_transport.h> | 32 | #include <scsi/scsi_transport.h> |
30 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
@@ -68,6 +71,7 @@ MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); | |||
68 | 71 | ||
69 | static struct libfc_function_template fnic_transport_template = { | 72 | static struct libfc_function_template fnic_transport_template = { |
70 | .frame_send = fnic_send, | 73 | .frame_send = fnic_send, |
74 | .lport_set_port_id = fnic_set_port_id, | ||
71 | .fcp_abort_io = fnic_empty_scsi_cleanup, | 75 | .fcp_abort_io = fnic_empty_scsi_cleanup, |
72 | .fcp_cleanup = fnic_empty_scsi_cleanup, | 76 | .fcp_cleanup = fnic_empty_scsi_cleanup, |
73 | .exch_mgr_reset = fnic_exch_mgr_reset | 77 | .exch_mgr_reset = fnic_exch_mgr_reset |
@@ -140,6 +144,7 @@ static struct fc_function_template fnic_fc_functions = { | |||
140 | .get_fc_host_stats = fnic_get_stats, | 144 | .get_fc_host_stats = fnic_get_stats, |
141 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), | 145 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), |
142 | .terminate_rport_io = fnic_terminate_rport_io, | 146 | .terminate_rport_io = fnic_terminate_rport_io, |
147 | .bsg_request = fc_lport_bsg_request, | ||
143 | }; | 148 | }; |
144 | 149 | ||
145 | static void fnic_get_host_speed(struct Scsi_Host *shost) | 150 | static void fnic_get_host_speed(struct Scsi_Host *shost) |
@@ -324,9 +329,6 @@ static int fnic_cleanup(struct fnic *fnic) | |||
324 | { | 329 | { |
325 | unsigned int i; | 330 | unsigned int i; |
326 | int err; | 331 | int err; |
327 | unsigned long flags; | ||
328 | struct fc_frame *flogi = NULL; | ||
329 | struct fc_frame *flogi_resp = NULL; | ||
330 | 332 | ||
331 | vnic_dev_disable(fnic->vdev); | 333 | vnic_dev_disable(fnic->vdev); |
332 | for (i = 0; i < fnic->intr_count; i++) | 334 | for (i = 0; i < fnic->intr_count; i++) |
@@ -367,24 +369,6 @@ static int fnic_cleanup(struct fnic *fnic) | |||
367 | for (i = 0; i < fnic->intr_count; i++) | 369 | for (i = 0; i < fnic->intr_count; i++) |
368 | vnic_intr_clean(&fnic->intr[i]); | 370 | vnic_intr_clean(&fnic->intr[i]); |
369 | 371 | ||
370 | /* | ||
371 | * Remove cached flogi and flogi resp frames if any | ||
372 | * These frames are not in any queue, and therefore queue | ||
373 | * cleanup does not clean them. So clean them explicitly | ||
374 | */ | ||
375 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
376 | flogi = fnic->flogi; | ||
377 | fnic->flogi = NULL; | ||
378 | flogi_resp = fnic->flogi_resp; | ||
379 | fnic->flogi_resp = NULL; | ||
380 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
381 | |||
382 | if (flogi) | ||
383 | dev_kfree_skb(fp_skb(flogi)); | ||
384 | |||
385 | if (flogi_resp) | ||
386 | dev_kfree_skb(fp_skb(flogi_resp)); | ||
387 | |||
388 | mempool_destroy(fnic->io_req_pool); | 372 | mempool_destroy(fnic->io_req_pool); |
389 | for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) | 373 | for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) |
390 | mempool_destroy(fnic->io_sgl_pool[i]); | 374 | mempool_destroy(fnic->io_sgl_pool[i]); |
@@ -409,6 +393,17 @@ static void *fnic_alloc_slab_dma(gfp_t gfp_mask, void *pool_data) | |||
409 | return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA); | 393 | return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA); |
410 | } | 394 | } |
411 | 395 | ||
396 | /** | ||
397 | * fnic_get_mac() - get assigned data MAC address for FIP code. | ||
398 | * @lport: local port. | ||
399 | */ | ||
400 | static u8 *fnic_get_mac(struct fc_lport *lport) | ||
401 | { | ||
402 | struct fnic *fnic = lport_priv(lport); | ||
403 | |||
404 | return fnic->data_src_addr; | ||
405 | } | ||
406 | |||
412 | static int __devinit fnic_probe(struct pci_dev *pdev, | 407 | static int __devinit fnic_probe(struct pci_dev *pdev, |
413 | const struct pci_device_id *ent) | 408 | const struct pci_device_id *ent) |
414 | { | 409 | { |
@@ -424,17 +419,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
424 | * Allocate SCSI Host and set up association between host, | 419 | * Allocate SCSI Host and set up association between host, |
425 | * local port, and fnic | 420 | * local port, and fnic |
426 | */ | 421 | */ |
427 | host = scsi_host_alloc(&fnic_host_template, | 422 | lp = libfc_host_alloc(&fnic_host_template, sizeof(struct fnic)); |
428 | sizeof(struct fc_lport) + sizeof(struct fnic)); | 423 | if (!lp) { |
429 | if (!host) { | 424 | printk(KERN_ERR PFX "Unable to alloc libfc local port\n"); |
430 | printk(KERN_ERR PFX "Unable to alloc SCSI host\n"); | ||
431 | err = -ENOMEM; | 425 | err = -ENOMEM; |
432 | goto err_out; | 426 | goto err_out; |
433 | } | 427 | } |
434 | lp = shost_priv(host); | 428 | host = lp->host; |
435 | lp->host = host; | ||
436 | fnic = lport_priv(lp); | 429 | fnic = lport_priv(lp); |
437 | fnic->lport = lp; | 430 | fnic->lport = lp; |
431 | fnic->ctlr.lp = lp; | ||
438 | 432 | ||
439 | snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, | 433 | snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, |
440 | host->host_no); | 434 | host->host_no); |
@@ -543,12 +537,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
543 | goto err_out_dev_close; | 537 | goto err_out_dev_close; |
544 | } | 538 | } |
545 | 539 | ||
546 | err = vnic_dev_mac_addr(fnic->vdev, fnic->mac_addr); | 540 | err = vnic_dev_mac_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); |
547 | if (err) { | 541 | if (err) { |
548 | shost_printk(KERN_ERR, fnic->lport->host, | 542 | shost_printk(KERN_ERR, fnic->lport->host, |
549 | "vNIC get MAC addr failed \n"); | 543 | "vNIC get MAC addr failed \n"); |
550 | goto err_out_dev_close; | 544 | goto err_out_dev_close; |
551 | } | 545 | } |
546 | /* set data_src for point-to-point mode and to keep it non-zero */ | ||
547 | memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN); | ||
552 | 548 | ||
553 | /* Get vNIC configuration */ | 549 | /* Get vNIC configuration */ |
554 | err = fnic_get_vnic_config(fnic); | 550 | err = fnic_get_vnic_config(fnic); |
@@ -560,6 +556,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
560 | } | 556 | } |
561 | host->max_lun = fnic->config.luns_per_tgt; | 557 | host->max_lun = fnic->config.luns_per_tgt; |
562 | host->max_id = FNIC_MAX_FCP_TARGET; | 558 | host->max_id = FNIC_MAX_FCP_TARGET; |
559 | host->max_cmd_len = FNIC_MAX_CMD_LEN; | ||
563 | 560 | ||
564 | fnic_get_res_counts(fnic); | 561 | fnic_get_res_counts(fnic); |
565 | 562 | ||
@@ -571,19 +568,12 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
571 | goto err_out_dev_close; | 568 | goto err_out_dev_close; |
572 | } | 569 | } |
573 | 570 | ||
574 | err = fnic_request_intr(fnic); | ||
575 | if (err) { | ||
576 | shost_printk(KERN_ERR, fnic->lport->host, | ||
577 | "Unable to request irq.\n"); | ||
578 | goto err_out_clear_intr; | ||
579 | } | ||
580 | |||
581 | err = fnic_alloc_vnic_resources(fnic); | 571 | err = fnic_alloc_vnic_resources(fnic); |
582 | if (err) { | 572 | if (err) { |
583 | shost_printk(KERN_ERR, fnic->lport->host, | 573 | shost_printk(KERN_ERR, fnic->lport->host, |
584 | "Failed to alloc vNIC resources, " | 574 | "Failed to alloc vNIC resources, " |
585 | "aborting.\n"); | 575 | "aborting.\n"); |
586 | goto err_out_free_intr; | 576 | goto err_out_clear_intr; |
587 | } | 577 | } |
588 | 578 | ||
589 | 579 | ||
@@ -623,9 +613,23 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
623 | fnic->vlan_hw_insert = 1; | 613 | fnic->vlan_hw_insert = 1; |
624 | fnic->vlan_id = 0; | 614 | fnic->vlan_id = 0; |
625 | 615 | ||
626 | fnic->flogi_oxid = FC_XID_UNKNOWN; | 616 | /* Initialize the FIP fcoe_ctrl struct */ |
627 | fnic->flogi = NULL; | 617 | fnic->ctlr.send = fnic_eth_send; |
628 | fnic->flogi_resp = NULL; | 618 | fnic->ctlr.update_mac = fnic_update_mac; |
619 | fnic->ctlr.get_src_addr = fnic_get_mac; | ||
620 | fcoe_ctlr_init(&fnic->ctlr); | ||
621 | if (fnic->config.flags & VFCF_FIP_CAPABLE) { | ||
622 | shost_printk(KERN_INFO, fnic->lport->host, | ||
623 | "firmware supports FIP\n"); | ||
624 | /* enable directed and multicast */ | ||
625 | vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0); | ||
626 | vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS); | ||
627 | vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); | ||
628 | } else { | ||
629 | shost_printk(KERN_INFO, fnic->lport->host, | ||
630 | "firmware uses non-FIP mode\n"); | ||
631 | fnic->ctlr.mode = FIP_ST_NON_FIP; | ||
632 | } | ||
629 | fnic->state = FNIC_IN_FC_MODE; | 633 | fnic->state = FNIC_IN_FC_MODE; |
630 | 634 | ||
631 | /* Enable hardware stripping of vlan header on ingress */ | 635 | /* Enable hardware stripping of vlan header on ingress */ |
@@ -697,6 +701,8 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
697 | goto err_out_remove_scsi_host; | 701 | goto err_out_remove_scsi_host; |
698 | } | 702 | } |
699 | 703 | ||
704 | fc_lport_init_stats(lp); | ||
705 | |||
700 | fc_lport_config(lp); | 706 | fc_lport_config(lp); |
701 | 707 | ||
702 | if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + | 708 | if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + |
@@ -716,6 +722,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
716 | INIT_WORK(&fnic->link_work, fnic_handle_link); | 722 | INIT_WORK(&fnic->link_work, fnic_handle_link); |
717 | INIT_WORK(&fnic->frame_work, fnic_handle_frame); | 723 | INIT_WORK(&fnic->frame_work, fnic_handle_frame); |
718 | skb_queue_head_init(&fnic->frame_queue); | 724 | skb_queue_head_init(&fnic->frame_queue); |
725 | skb_queue_head_init(&fnic->tx_queue); | ||
719 | 726 | ||
720 | /* Enable all queues */ | 727 | /* Enable all queues */ |
721 | for (i = 0; i < fnic->raw_wq_count; i++) | 728 | for (i = 0; i < fnic->raw_wq_count; i++) |
@@ -728,6 +735,14 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
728 | fc_fabric_login(lp); | 735 | fc_fabric_login(lp); |
729 | 736 | ||
730 | vnic_dev_enable(fnic->vdev); | 737 | vnic_dev_enable(fnic->vdev); |
738 | |||
739 | err = fnic_request_intr(fnic); | ||
740 | if (err) { | ||
741 | shost_printk(KERN_ERR, fnic->lport->host, | ||
742 | "Unable to request irq.\n"); | ||
743 | goto err_out_free_exch_mgr; | ||
744 | } | ||
745 | |||
731 | for (i = 0; i < fnic->intr_count; i++) | 746 | for (i = 0; i < fnic->intr_count; i++) |
732 | vnic_intr_unmask(&fnic->intr[i]); | 747 | vnic_intr_unmask(&fnic->intr[i]); |
733 | 748 | ||
@@ -738,8 +753,8 @@ static int __devinit fnic_probe(struct pci_dev *pdev, | |||
738 | err_out_free_exch_mgr: | 753 | err_out_free_exch_mgr: |
739 | fc_exch_mgr_free(lp); | 754 | fc_exch_mgr_free(lp); |
740 | err_out_remove_scsi_host: | 755 | err_out_remove_scsi_host: |
741 | fc_remove_host(fnic->lport->host); | 756 | fc_remove_host(lp->host); |
742 | scsi_remove_host(fnic->lport->host); | 757 | scsi_remove_host(lp->host); |
743 | err_out_free_rq_buf: | 758 | err_out_free_rq_buf: |
744 | for (i = 0; i < fnic->rq_count; i++) | 759 | for (i = 0; i < fnic->rq_count; i++) |
745 | vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); | 760 | vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); |
@@ -752,8 +767,6 @@ err_out_free_ioreq_pool: | |||
752 | mempool_destroy(fnic->io_req_pool); | 767 | mempool_destroy(fnic->io_req_pool); |
753 | err_out_free_resources: | 768 | err_out_free_resources: |
754 | fnic_free_vnic_resources(fnic); | 769 | fnic_free_vnic_resources(fnic); |
755 | err_out_free_intr: | ||
756 | fnic_free_intr(fnic); | ||
757 | err_out_clear_intr: | 770 | err_out_clear_intr: |
758 | fnic_clear_intr_mode(fnic); | 771 | fnic_clear_intr_mode(fnic); |
759 | err_out_dev_close: | 772 | err_out_dev_close: |
@@ -775,6 +788,7 @@ err_out: | |||
775 | static void __devexit fnic_remove(struct pci_dev *pdev) | 788 | static void __devexit fnic_remove(struct pci_dev *pdev) |
776 | { | 789 | { |
777 | struct fnic *fnic = pci_get_drvdata(pdev); | 790 | struct fnic *fnic = pci_get_drvdata(pdev); |
791 | struct fc_lport *lp = fnic->lport; | ||
778 | unsigned long flags; | 792 | unsigned long flags; |
779 | 793 | ||
780 | /* | 794 | /* |
@@ -796,6 +810,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev) | |||
796 | */ | 810 | */ |
797 | flush_workqueue(fnic_event_queue); | 811 | flush_workqueue(fnic_event_queue); |
798 | skb_queue_purge(&fnic->frame_queue); | 812 | skb_queue_purge(&fnic->frame_queue); |
813 | skb_queue_purge(&fnic->tx_queue); | ||
799 | 814 | ||
800 | /* | 815 | /* |
801 | * Log off the fabric. This stops all remote ports, dns port, | 816 | * Log off the fabric. This stops all remote ports, dns port, |
@@ -808,7 +823,8 @@ static void __devexit fnic_remove(struct pci_dev *pdev) | |||
808 | fnic->in_remove = 1; | 823 | fnic->in_remove = 1; |
809 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | 824 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); |
810 | 825 | ||
811 | fc_lport_destroy(fnic->lport); | 826 | fcoe_ctlr_destroy(&fnic->ctlr); |
827 | fc_lport_destroy(lp); | ||
812 | 828 | ||
813 | /* | 829 | /* |
814 | * This stops the fnic device, masks all interrupts. Completed | 830 | * This stops the fnic device, masks all interrupts. Completed |
@@ -818,6 +834,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev) | |||
818 | fnic_cleanup(fnic); | 834 | fnic_cleanup(fnic); |
819 | 835 | ||
820 | BUG_ON(!skb_queue_empty(&fnic->frame_queue)); | 836 | BUG_ON(!skb_queue_empty(&fnic->frame_queue)); |
837 | BUG_ON(!skb_queue_empty(&fnic->tx_queue)); | ||
821 | 838 | ||
822 | spin_lock_irqsave(&fnic_list_lock, flags); | 839 | spin_lock_irqsave(&fnic_list_lock, flags); |
823 | list_del(&fnic->list); | 840 | list_del(&fnic->list); |
@@ -827,8 +844,8 @@ static void __devexit fnic_remove(struct pci_dev *pdev) | |||
827 | scsi_remove_host(fnic->lport->host); | 844 | scsi_remove_host(fnic->lport->host); |
828 | fc_exch_mgr_free(fnic->lport); | 845 | fc_exch_mgr_free(fnic->lport); |
829 | vnic_dev_notify_unset(fnic->vdev); | 846 | vnic_dev_notify_unset(fnic->vdev); |
830 | fnic_free_vnic_resources(fnic); | ||
831 | fnic_free_intr(fnic); | 847 | fnic_free_intr(fnic); |
848 | fnic_free_vnic_resources(fnic); | ||
832 | fnic_clear_intr_mode(fnic); | 849 | fnic_clear_intr_mode(fnic); |
833 | vnic_dev_close(fnic->vdev); | 850 | vnic_dev_close(fnic->vdev); |
834 | vnic_dev_unregister(fnic->vdev); | 851 | vnic_dev_unregister(fnic->vdev); |
@@ -836,7 +853,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev) | |||
836 | pci_release_regions(pdev); | 853 | pci_release_regions(pdev); |
837 | pci_disable_device(pdev); | 854 | pci_disable_device(pdev); |
838 | pci_set_drvdata(pdev, NULL); | 855 | pci_set_drvdata(pdev, NULL); |
839 | scsi_host_put(fnic->lport->host); | 856 | scsi_host_put(lp->host); |
840 | } | 857 | } |
841 | 858 | ||
842 | static struct pci_driver fnic_driver = { | 859 | static struct pci_driver fnic_driver = { |