diff options
author | Krishna Gudipati <kgudipat@brocade.com> | 2011-07-20 20:03:46 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-07-27 06:54:03 -0400 |
commit | 45c5dc1d3f42d4f54a5ab5f45ee55f0ffe1099f1 (patch) | |
tree | d0a5f76929e47c6876f6db5b9a03a1d60c2d9b62 /drivers/scsi/bfa/bfa_ioc.c | |
parent | c0350bf57445b9e2a4369668127ecc4431472d26 (diff) |
[SCSI] bfa: Add support to store driver configuration in flash.
- Added dconf (Driver Config) BFA sub-module.
- The dconf sub-module provides interfaces and manages flash writes
to the flash DRV parition.
- dconf sub-module also ensures that the whole 64K DRV partition is updated
on a flash write.
Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bfa/bfa_ioc.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 27c5565ba2c3..1ac5aecf25a6 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c | |||
@@ -5588,3 +5588,396 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) | |||
5588 | WARN_ON(1); | 5588 | WARN_ON(1); |
5589 | } | 5589 | } |
5590 | } | 5590 | } |
5591 | |||
5592 | /* | ||
5593 | * DCONF module specific | ||
5594 | */ | ||
5595 | |||
5596 | BFA_MODULE(dconf); | ||
5597 | |||
5598 | /* | ||
5599 | * DCONF state machine events | ||
5600 | */ | ||
5601 | enum bfa_dconf_event { | ||
5602 | BFA_DCONF_SM_INIT = 1, /* dconf Init */ | ||
5603 | BFA_DCONF_SM_FLASH_COMP = 2, /* read/write to flash */ | ||
5604 | BFA_DCONF_SM_WR = 3, /* binding change, map */ | ||
5605 | BFA_DCONF_SM_TIMEOUT = 4, /* Start timer */ | ||
5606 | BFA_DCONF_SM_EXIT = 5, /* exit dconf module */ | ||
5607 | BFA_DCONF_SM_IOCDISABLE = 6, /* IOC disable event */ | ||
5608 | }; | ||
5609 | |||
5610 | /* forward declaration of DCONF state machine */ | ||
5611 | static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, | ||
5612 | enum bfa_dconf_event event); | ||
5613 | static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf, | ||
5614 | enum bfa_dconf_event event); | ||
5615 | static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, | ||
5616 | enum bfa_dconf_event event); | ||
5617 | static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, | ||
5618 | enum bfa_dconf_event event); | ||
5619 | static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, | ||
5620 | enum bfa_dconf_event event); | ||
5621 | static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf, | ||
5622 | enum bfa_dconf_event event); | ||
5623 | static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf, | ||
5624 | enum bfa_dconf_event event); | ||
5625 | |||
5626 | static void bfa_dconf_cbfn(void *dconf, bfa_status_t status); | ||
5627 | static void bfa_dconf_timer(void *cbarg); | ||
5628 | static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf); | ||
5629 | static void bfa_dconf_init_cb(void *arg, bfa_status_t status); | ||
5630 | |||
5631 | /* | ||
5632 | * Begining state of dconf module. Waiting for an event to start. | ||
5633 | */ | ||
5634 | static void | ||
5635 | bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) | ||
5636 | { | ||
5637 | bfa_status_t bfa_status; | ||
5638 | bfa_trc(dconf->bfa, event); | ||
5639 | |||
5640 | switch (event) { | ||
5641 | case BFA_DCONF_SM_INIT: | ||
5642 | if (dconf->min_cfg) { | ||
5643 | bfa_trc(dconf->bfa, dconf->min_cfg); | ||
5644 | return; | ||
5645 | } | ||
5646 | bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read); | ||
5647 | dconf->flashdone = BFA_FALSE; | ||
5648 | bfa_trc(dconf->bfa, dconf->flashdone); | ||
5649 | bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa), | ||
5650 | BFA_FLASH_PART_DRV, dconf->instance, | ||
5651 | dconf->dconf, | ||
5652 | sizeof(struct bfa_dconf_s), 0, | ||
5653 | bfa_dconf_init_cb, dconf->bfa); | ||
5654 | if (bfa_status != BFA_STATUS_OK) { | ||
5655 | bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED); | ||
5656 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5657 | return; | ||
5658 | } | ||
5659 | break; | ||
5660 | case BFA_DCONF_SM_EXIT: | ||
5661 | dconf->flashdone = BFA_TRUE; | ||
5662 | case BFA_DCONF_SM_IOCDISABLE: | ||
5663 | case BFA_DCONF_SM_WR: | ||
5664 | case BFA_DCONF_SM_FLASH_COMP: | ||
5665 | break; | ||
5666 | default: | ||
5667 | bfa_sm_fault(dconf->bfa, event); | ||
5668 | } | ||
5669 | } | ||
5670 | |||
5671 | /* | ||
5672 | * Read flash for dconf entries and make a call back to the driver once done. | ||
5673 | */ | ||
5674 | static void | ||
5675 | bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf, | ||
5676 | enum bfa_dconf_event event) | ||
5677 | { | ||
5678 | bfa_trc(dconf->bfa, event); | ||
5679 | |||
5680 | switch (event) { | ||
5681 | case BFA_DCONF_SM_FLASH_COMP: | ||
5682 | bfa_sm_set_state(dconf, bfa_dconf_sm_ready); | ||
5683 | break; | ||
5684 | case BFA_DCONF_SM_TIMEOUT: | ||
5685 | bfa_sm_set_state(dconf, bfa_dconf_sm_ready); | ||
5686 | break; | ||
5687 | case BFA_DCONF_SM_EXIT: | ||
5688 | dconf->flashdone = BFA_TRUE; | ||
5689 | bfa_trc(dconf->bfa, dconf->flashdone); | ||
5690 | case BFA_DCONF_SM_IOCDISABLE: | ||
5691 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5692 | break; | ||
5693 | default: | ||
5694 | bfa_sm_fault(dconf->bfa, event); | ||
5695 | } | ||
5696 | } | ||
5697 | |||
5698 | /* | ||
5699 | * DCONF Module is in ready state. Has completed the initialization. | ||
5700 | */ | ||
5701 | static void | ||
5702 | bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) | ||
5703 | { | ||
5704 | bfa_trc(dconf->bfa, event); | ||
5705 | |||
5706 | switch (event) { | ||
5707 | case BFA_DCONF_SM_WR: | ||
5708 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5709 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5710 | bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); | ||
5711 | break; | ||
5712 | case BFA_DCONF_SM_EXIT: | ||
5713 | dconf->flashdone = BFA_TRUE; | ||
5714 | bfa_trc(dconf->bfa, dconf->flashdone); | ||
5715 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5716 | break; | ||
5717 | case BFA_DCONF_SM_INIT: | ||
5718 | case BFA_DCONF_SM_IOCDISABLE: | ||
5719 | break; | ||
5720 | default: | ||
5721 | bfa_sm_fault(dconf->bfa, event); | ||
5722 | } | ||
5723 | } | ||
5724 | |||
5725 | /* | ||
5726 | * entries are dirty, write back to the flash. | ||
5727 | */ | ||
5728 | |||
5729 | static void | ||
5730 | bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) | ||
5731 | { | ||
5732 | bfa_trc(dconf->bfa, event); | ||
5733 | |||
5734 | switch (event) { | ||
5735 | case BFA_DCONF_SM_TIMEOUT: | ||
5736 | bfa_sm_set_state(dconf, bfa_dconf_sm_sync); | ||
5737 | bfa_dconf_flash_write(dconf); | ||
5738 | break; | ||
5739 | case BFA_DCONF_SM_WR: | ||
5740 | bfa_timer_stop(&dconf->timer); | ||
5741 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5742 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5743 | break; | ||
5744 | case BFA_DCONF_SM_EXIT: | ||
5745 | bfa_timer_stop(&dconf->timer); | ||
5746 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5747 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5748 | bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync); | ||
5749 | bfa_dconf_flash_write(dconf); | ||
5750 | break; | ||
5751 | case BFA_DCONF_SM_FLASH_COMP: | ||
5752 | break; | ||
5753 | case BFA_DCONF_SM_IOCDISABLE: | ||
5754 | bfa_timer_stop(&dconf->timer); | ||
5755 | bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty); | ||
5756 | break; | ||
5757 | default: | ||
5758 | bfa_sm_fault(dconf->bfa, event); | ||
5759 | } | ||
5760 | } | ||
5761 | |||
5762 | /* | ||
5763 | * Sync the dconf entries to the flash. | ||
5764 | */ | ||
5765 | static void | ||
5766 | bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf, | ||
5767 | enum bfa_dconf_event event) | ||
5768 | { | ||
5769 | bfa_trc(dconf->bfa, event); | ||
5770 | |||
5771 | switch (event) { | ||
5772 | case BFA_DCONF_SM_IOCDISABLE: | ||
5773 | case BFA_DCONF_SM_FLASH_COMP: | ||
5774 | bfa_timer_stop(&dconf->timer); | ||
5775 | case BFA_DCONF_SM_TIMEOUT: | ||
5776 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5777 | dconf->flashdone = BFA_TRUE; | ||
5778 | bfa_trc(dconf->bfa, dconf->flashdone); | ||
5779 | bfa_ioc_disable(&dconf->bfa->ioc); | ||
5780 | break; | ||
5781 | default: | ||
5782 | bfa_sm_fault(dconf->bfa, event); | ||
5783 | } | ||
5784 | } | ||
5785 | |||
5786 | static void | ||
5787 | bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) | ||
5788 | { | ||
5789 | bfa_trc(dconf->bfa, event); | ||
5790 | |||
5791 | switch (event) { | ||
5792 | case BFA_DCONF_SM_FLASH_COMP: | ||
5793 | bfa_sm_set_state(dconf, bfa_dconf_sm_ready); | ||
5794 | break; | ||
5795 | case BFA_DCONF_SM_WR: | ||
5796 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5797 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5798 | bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); | ||
5799 | break; | ||
5800 | case BFA_DCONF_SM_EXIT: | ||
5801 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5802 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5803 | bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync); | ||
5804 | break; | ||
5805 | case BFA_DCONF_SM_IOCDISABLE: | ||
5806 | bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty); | ||
5807 | break; | ||
5808 | default: | ||
5809 | bfa_sm_fault(dconf->bfa, event); | ||
5810 | } | ||
5811 | } | ||
5812 | |||
5813 | static void | ||
5814 | bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf, | ||
5815 | enum bfa_dconf_event event) | ||
5816 | { | ||
5817 | bfa_trc(dconf->bfa, event); | ||
5818 | |||
5819 | switch (event) { | ||
5820 | case BFA_DCONF_SM_INIT: | ||
5821 | bfa_timer_start(dconf->bfa, &dconf->timer, | ||
5822 | bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); | ||
5823 | bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); | ||
5824 | break; | ||
5825 | case BFA_DCONF_SM_EXIT: | ||
5826 | dconf->flashdone = BFA_TRUE; | ||
5827 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5828 | break; | ||
5829 | case BFA_DCONF_SM_IOCDISABLE: | ||
5830 | break; | ||
5831 | default: | ||
5832 | bfa_sm_fault(dconf->bfa, event); | ||
5833 | } | ||
5834 | } | ||
5835 | |||
5836 | /* | ||
5837 | * Compute and return memory needed by DRV_CFG module. | ||
5838 | */ | ||
5839 | static void | ||
5840 | bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, | ||
5841 | struct bfa_s *bfa) | ||
5842 | { | ||
5843 | struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa); | ||
5844 | |||
5845 | if (cfg->drvcfg.min_cfg) | ||
5846 | bfa_mem_kva_setup(meminfo, dconf_kva, | ||
5847 | sizeof(struct bfa_dconf_hdr_s)); | ||
5848 | else | ||
5849 | bfa_mem_kva_setup(meminfo, dconf_kva, | ||
5850 | sizeof(struct bfa_dconf_s)); | ||
5851 | } | ||
5852 | |||
5853 | static void | ||
5854 | bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, | ||
5855 | struct bfa_pcidev_s *pcidev) | ||
5856 | { | ||
5857 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5858 | |||
5859 | dconf->bfad = bfad; | ||
5860 | dconf->bfa = bfa; | ||
5861 | dconf->instance = bfa->ioc.port_id; | ||
5862 | bfa_trc(bfa, dconf->instance); | ||
5863 | |||
5864 | dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf); | ||
5865 | if (cfg->drvcfg.min_cfg) { | ||
5866 | bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s); | ||
5867 | dconf->min_cfg = BFA_TRUE; | ||
5868 | /* | ||
5869 | * Set the flashdone flag to TRUE explicitly as no flash | ||
5870 | * write will happen in min_cfg mode. | ||
5871 | */ | ||
5872 | dconf->flashdone = BFA_TRUE; | ||
5873 | } else { | ||
5874 | dconf->min_cfg = BFA_FALSE; | ||
5875 | bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s); | ||
5876 | } | ||
5877 | |||
5878 | bfa_dconf_read_data_valid(bfa) = BFA_FALSE; | ||
5879 | bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); | ||
5880 | } | ||
5881 | |||
5882 | static void | ||
5883 | bfa_dconf_init_cb(void *arg, bfa_status_t status) | ||
5884 | { | ||
5885 | struct bfa_s *bfa = arg; | ||
5886 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5887 | |||
5888 | dconf->flashdone = BFA_TRUE; | ||
5889 | bfa_trc(bfa, dconf->flashdone); | ||
5890 | bfa_iocfc_cb_dconf_modinit(bfa, status); | ||
5891 | if (status == BFA_STATUS_OK) { | ||
5892 | bfa_dconf_read_data_valid(bfa) = BFA_TRUE; | ||
5893 | if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE) | ||
5894 | dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE; | ||
5895 | if (dconf->dconf->hdr.version != BFI_DCONF_VERSION) | ||
5896 | dconf->dconf->hdr.version = BFI_DCONF_VERSION; | ||
5897 | } | ||
5898 | bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); | ||
5899 | } | ||
5900 | |||
5901 | void | ||
5902 | bfa_dconf_modinit(struct bfa_s *bfa) | ||
5903 | { | ||
5904 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5905 | bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT); | ||
5906 | } | ||
5907 | static void | ||
5908 | bfa_dconf_start(struct bfa_s *bfa) | ||
5909 | { | ||
5910 | } | ||
5911 | |||
5912 | static void | ||
5913 | bfa_dconf_stop(struct bfa_s *bfa) | ||
5914 | { | ||
5915 | } | ||
5916 | |||
5917 | static void bfa_dconf_timer(void *cbarg) | ||
5918 | { | ||
5919 | struct bfa_dconf_mod_s *dconf = cbarg; | ||
5920 | bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT); | ||
5921 | } | ||
5922 | static void | ||
5923 | bfa_dconf_iocdisable(struct bfa_s *bfa) | ||
5924 | { | ||
5925 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5926 | bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE); | ||
5927 | } | ||
5928 | |||
5929 | static void | ||
5930 | bfa_dconf_detach(struct bfa_s *bfa) | ||
5931 | { | ||
5932 | } | ||
5933 | |||
5934 | static bfa_status_t | ||
5935 | bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf) | ||
5936 | { | ||
5937 | bfa_status_t bfa_status; | ||
5938 | bfa_trc(dconf->bfa, 0); | ||
5939 | |||
5940 | bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa), | ||
5941 | BFA_FLASH_PART_DRV, dconf->instance, | ||
5942 | dconf->dconf, sizeof(struct bfa_dconf_s), 0, | ||
5943 | bfa_dconf_cbfn, dconf); | ||
5944 | if (bfa_status != BFA_STATUS_OK) | ||
5945 | WARN_ON(bfa_status); | ||
5946 | bfa_trc(dconf->bfa, bfa_status); | ||
5947 | |||
5948 | return bfa_status; | ||
5949 | } | ||
5950 | |||
5951 | bfa_status_t | ||
5952 | bfa_dconf_update(struct bfa_s *bfa) | ||
5953 | { | ||
5954 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5955 | bfa_trc(dconf->bfa, 0); | ||
5956 | if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty)) | ||
5957 | return BFA_STATUS_FAILED; | ||
5958 | |||
5959 | if (dconf->min_cfg) { | ||
5960 | bfa_trc(dconf->bfa, dconf->min_cfg); | ||
5961 | return BFA_STATUS_FAILED; | ||
5962 | } | ||
5963 | |||
5964 | bfa_sm_send_event(dconf, BFA_DCONF_SM_WR); | ||
5965 | return BFA_STATUS_OK; | ||
5966 | } | ||
5967 | |||
5968 | static void | ||
5969 | bfa_dconf_cbfn(void *arg, bfa_status_t status) | ||
5970 | { | ||
5971 | struct bfa_dconf_mod_s *dconf = arg; | ||
5972 | WARN_ON(status); | ||
5973 | bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); | ||
5974 | } | ||
5975 | |||
5976 | void | ||
5977 | bfa_dconf_modexit(struct bfa_s *bfa) | ||
5978 | { | ||
5979 | struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); | ||
5980 | BFA_DCONF_MOD(bfa)->flashdone = BFA_FALSE; | ||
5981 | bfa_trc(bfa, BFA_DCONF_MOD(bfa)->flashdone); | ||
5982 | bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT); | ||
5983 | } | ||