diff options
author | James Smart <james.smart@emulex.com> | 2011-05-24 11:42:45 -0400 |
---|---|---|
committer | James Bottomley <jbottomley@parallels.com> | 2011-05-26 23:49:37 -0400 |
commit | 52d5244096017bbd11164479116baceaede342b0 (patch) | |
tree | 1e61c05ab7f1babd2ed44f6136bc6f9384d9f786 /drivers | |
parent | 912e3acde60b3b9ebf46c5ec5ae6bd01b80132c8 (diff) |
[SCSI] lpfc 8.3.24: Add request-firmware support
Add request-firmware support:
- Add support for request_firmware interface for INTF2 SLI4 ports.
- Add ability to reset SLI4 INTF2 ports.
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <jbottomley@parallels.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 33 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 44 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 102 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 90 |
5 files changed, 259 insertions, 11 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6ecd6daffc15..135a53baa735 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -755,18 +755,18 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, | |||
755 | } | 755 | } |
756 | 756 | ||
757 | /** | 757 | /** |
758 | * lpfc_sli4_fw_dump_request - Request firmware to perform a firmware dump | 758 | * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc |
759 | * @phba: lpfc_hba pointer. | 759 | * @phba: lpfc_hba pointer. |
760 | * | 760 | * |
761 | * Description: | 761 | * Description: |
762 | * Request SLI4 interface type-2 device to perform a dump of firmware dump | 762 | * Request SLI4 interface type-2 device to perform a physical register set |
763 | * object into it's /dbg directory of the flash file system. | 763 | * access. |
764 | * | 764 | * |
765 | * Returns: | 765 | * Returns: |
766 | * zero for success | 766 | * zero for success |
767 | **/ | 767 | **/ |
768 | static ssize_t | 768 | static ssize_t |
769 | lpfc_sli4_fw_dump_request(struct lpfc_hba *phba) | 769 | lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) |
770 | { | 770 | { |
771 | struct completion online_compl; | 771 | struct completion online_compl; |
772 | uint32_t reg_val; | 772 | uint32_t reg_val; |
@@ -776,6 +776,11 @@ lpfc_sli4_fw_dump_request(struct lpfc_hba *phba) | |||
776 | if (!phba->cfg_enable_hba_reset) | 776 | if (!phba->cfg_enable_hba_reset) |
777 | return -EIO; | 777 | return -EIO; |
778 | 778 | ||
779 | if ((phba->sli_rev < LPFC_SLI_REV4) || | ||
780 | (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != | ||
781 | LPFC_SLI_INTF_IF_TYPE_2)) | ||
782 | return -EPERM; | ||
783 | |||
779 | status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); | 784 | status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); |
780 | 785 | ||
781 | if (status != 0) | 786 | if (status != 0) |
@@ -786,7 +791,14 @@ lpfc_sli4_fw_dump_request(struct lpfc_hba *phba) | |||
786 | 791 | ||
787 | reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + | 792 | reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + |
788 | LPFC_CTL_PDEV_CTL_OFFSET); | 793 | LPFC_CTL_PDEV_CTL_OFFSET); |
789 | reg_val |= LPFC_FW_DUMP_REQUEST; | 794 | |
795 | if (opcode == LPFC_FW_DUMP) | ||
796 | reg_val |= LPFC_FW_DUMP_REQUEST; | ||
797 | else if (opcode == LPFC_FW_RESET) | ||
798 | reg_val |= LPFC_CTL_PDEV_CTL_FRST; | ||
799 | else if (opcode == LPFC_DV_RESET) | ||
800 | reg_val |= LPFC_CTL_PDEV_CTL_DRST; | ||
801 | |||
790 | writel(reg_val, phba->sli4_hba.conf_regs_memmap_p + | 802 | writel(reg_val, phba->sli4_hba.conf_regs_memmap_p + |
791 | LPFC_CTL_PDEV_CTL_OFFSET); | 803 | LPFC_CTL_PDEV_CTL_OFFSET); |
792 | /* flush */ | 804 | /* flush */ |
@@ -904,12 +916,11 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, | |||
904 | else | 916 | else |
905 | status = lpfc_do_offline(phba, LPFC_EVT_KILL); | 917 | status = lpfc_do_offline(phba, LPFC_EVT_KILL); |
906 | else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0) | 918 | else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0) |
907 | if ((phba->sli_rev < LPFC_SLI_REV4) || | 919 | status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP); |
908 | (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != | 920 | else if (strncmp(buf, "fw_reset", sizeof("fw_reset") - 1) == 0) |
909 | LPFC_SLI_INTF_IF_TYPE_2)) | 921 | status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET); |
910 | return -EPERM; | 922 | else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0) |
911 | else | 923 | status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); |
912 | status = lpfc_sli4_fw_dump_request(phba); | ||
913 | else | 924 | else |
914 | return -EINVAL; | 925 | return -EINVAL; |
915 | 926 | ||
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 3b9a6152b7f9..0b63cb2610d0 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -430,5 +430,6 @@ void lpfc_cleanup_wt_rrqs(struct lpfc_hba *); | |||
430 | void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *); | 430 | void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *); |
431 | struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t, | 431 | struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t, |
432 | uint32_t); | 432 | uint32_t); |
433 | int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *); | ||
433 | /* functions to support SR-IOV */ | 434 | /* functions to support SR-IOV */ |
434 | int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); | 435 | int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); |
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 115915d4a60a..61a40fd1ad18 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h | |||
@@ -821,6 +821,7 @@ struct mbox_header { | |||
821 | #define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A | 821 | #define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A |
822 | #define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0 | 822 | #define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0 |
823 | #define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4 | 823 | #define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4 |
824 | #define LPFC_MBOX_OPCODE_WRITE_OBJECT 0xAC | ||
824 | #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5 | 825 | #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5 |
825 | 826 | ||
826 | /* FCoE Opcodes */ | 827 | /* FCoE Opcodes */ |
@@ -2372,6 +2373,29 @@ struct lpfc_mbx_get_prof_cfg { | |||
2372 | #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 | 2373 | #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 |
2373 | #define MB_CQE_STATUS_DMA_FAILED 0x5 | 2374 | #define MB_CQE_STATUS_DMA_FAILED 0x5 |
2374 | 2375 | ||
2376 | #define LPFC_MBX_WR_CONFIG_MAX_BDE 8 | ||
2377 | struct lpfc_mbx_wr_object { | ||
2378 | struct mbox_header header; | ||
2379 | union { | ||
2380 | struct { | ||
2381 | uint32_t word4; | ||
2382 | #define lpfc_wr_object_eof_SHIFT 31 | ||
2383 | #define lpfc_wr_object_eof_MASK 0x00000001 | ||
2384 | #define lpfc_wr_object_eof_WORD word4 | ||
2385 | #define lpfc_wr_object_write_length_SHIFT 0 | ||
2386 | #define lpfc_wr_object_write_length_MASK 0x00FFFFFF | ||
2387 | #define lpfc_wr_object_write_length_WORD word4 | ||
2388 | uint32_t write_offset; | ||
2389 | uint32_t object_name[26]; | ||
2390 | uint32_t bde_count; | ||
2391 | struct ulp_bde64 bde[LPFC_MBX_WR_CONFIG_MAX_BDE]; | ||
2392 | } request; | ||
2393 | struct { | ||
2394 | uint32_t actual_write_length; | ||
2395 | } response; | ||
2396 | } u; | ||
2397 | }; | ||
2398 | |||
2375 | /* mailbox queue entry structure */ | 2399 | /* mailbox queue entry structure */ |
2376 | struct lpfc_mqe { | 2400 | struct lpfc_mqe { |
2377 | uint32_t word0; | 2401 | uint32_t word0; |
@@ -2421,6 +2445,7 @@ struct lpfc_mqe { | |||
2421 | struct lpfc_mbx_get_func_cfg get_func_cfg; | 2445 | struct lpfc_mbx_get_func_cfg get_func_cfg; |
2422 | struct lpfc_mbx_get_prof_cfg get_prof_cfg; | 2446 | struct lpfc_mbx_get_prof_cfg get_prof_cfg; |
2423 | struct lpfc_mbx_nop nop; | 2447 | struct lpfc_mbx_nop nop; |
2448 | struct lpfc_mbx_wr_object wr_object; | ||
2424 | } un; | 2449 | } un; |
2425 | }; | 2450 | }; |
2426 | 2451 | ||
@@ -2966,9 +2991,28 @@ union lpfc_wqe { | |||
2966 | struct gen_req64_wqe gen_req; | 2991 | struct gen_req64_wqe gen_req; |
2967 | }; | 2992 | }; |
2968 | 2993 | ||
2994 | #define LPFC_GROUP_OJECT_MAGIC_NUM 0xfeaa0001 | ||
2995 | #define LPFC_FILE_TYPE_GROUP 0xf7 | ||
2996 | #define LPFC_FILE_ID_GROUP 0xa2 | ||
2997 | struct lpfc_grp_hdr { | ||
2998 | uint32_t size; | ||
2999 | uint32_t magic_number; | ||
3000 | uint32_t word2; | ||
3001 | #define lpfc_grp_hdr_file_type_SHIFT 24 | ||
3002 | #define lpfc_grp_hdr_file_type_MASK 0x000000FF | ||
3003 | #define lpfc_grp_hdr_file_type_WORD word2 | ||
3004 | #define lpfc_grp_hdr_id_SHIFT 16 | ||
3005 | #define lpfc_grp_hdr_id_MASK 0x000000FF | ||
3006 | #define lpfc_grp_hdr_id_WORD word2 | ||
3007 | uint8_t rev_name[128]; | ||
3008 | }; | ||
3009 | |||
2969 | #define FCP_COMMAND 0x0 | 3010 | #define FCP_COMMAND 0x0 |
2970 | #define FCP_COMMAND_DATA_OUT 0x1 | 3011 | #define FCP_COMMAND_DATA_OUT 0x1 |
2971 | #define ELS_COMMAND_NON_FIP 0xC | 3012 | #define ELS_COMMAND_NON_FIP 0xC |
2972 | #define ELS_COMMAND_FIP 0xD | 3013 | #define ELS_COMMAND_FIP 0xD |
2973 | #define OTHER_COMMAND 0x8 | 3014 | #define OTHER_COMMAND 0x8 |
2974 | 3015 | ||
3016 | #define LPFC_FW_DUMP 1 | ||
3017 | #define LPFC_FW_RESET 2 | ||
3018 | #define LPFC_DV_RESET 3 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e81912cd257e..2b535cff4b2a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/aer.h> | 31 | #include <linux/aer.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/firmware.h> | ||
33 | 34 | ||
34 | #include <scsi/scsi.h> | 35 | #include <scsi/scsi.h> |
35 | #include <scsi/scsi_device.h> | 36 | #include <scsi/scsi_device.h> |
@@ -8775,6 +8776,97 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) | |||
8775 | } | 8776 | } |
8776 | 8777 | ||
8777 | /** | 8778 | /** |
8779 | * lpfc_write_firmware - attempt to write a firmware image to the port | ||
8780 | * @phba: pointer to lpfc hba data structure. | ||
8781 | * @fw: pointer to firmware image returned from request_firmware. | ||
8782 | * | ||
8783 | * returns the number of bytes written if write is successful. | ||
8784 | * returns a negative error value if there were errors. | ||
8785 | * returns 0 if firmware matches currently active firmware on port. | ||
8786 | **/ | ||
8787 | int | ||
8788 | lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) | ||
8789 | { | ||
8790 | char fwrev[32]; | ||
8791 | struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data; | ||
8792 | struct list_head dma_buffer_list; | ||
8793 | int i, rc = 0; | ||
8794 | struct lpfc_dmabuf *dmabuf, *next; | ||
8795 | uint32_t offset = 0, temp_offset = 0; | ||
8796 | |||
8797 | INIT_LIST_HEAD(&dma_buffer_list); | ||
8798 | if ((image->magic_number != LPFC_GROUP_OJECT_MAGIC_NUM) || | ||
8799 | (bf_get(lpfc_grp_hdr_file_type, image) != LPFC_FILE_TYPE_GROUP) || | ||
8800 | (bf_get(lpfc_grp_hdr_id, image) != LPFC_FILE_ID_GROUP) || | ||
8801 | (image->size != fw->size)) { | ||
8802 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8803 | "3022 Invalid FW image found. " | ||
8804 | "Magic:%d Type:%x ID:%x\n", | ||
8805 | image->magic_number, | ||
8806 | bf_get(lpfc_grp_hdr_file_type, image), | ||
8807 | bf_get(lpfc_grp_hdr_id, image)); | ||
8808 | return -EINVAL; | ||
8809 | } | ||
8810 | lpfc_decode_firmware_rev(phba, fwrev, 1); | ||
8811 | if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) { | ||
8812 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8813 | "3023 Updating Firmware. Current Version:%s " | ||
8814 | "New Version:%s\n", | ||
8815 | fwrev, image->rev_name); | ||
8816 | for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) { | ||
8817 | dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), | ||
8818 | GFP_KERNEL); | ||
8819 | if (!dmabuf) { | ||
8820 | rc = -ENOMEM; | ||
8821 | goto out; | ||
8822 | } | ||
8823 | dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, | ||
8824 | SLI4_PAGE_SIZE, | ||
8825 | &dmabuf->phys, | ||
8826 | GFP_KERNEL); | ||
8827 | if (!dmabuf->virt) { | ||
8828 | kfree(dmabuf); | ||
8829 | rc = -ENOMEM; | ||
8830 | goto out; | ||
8831 | } | ||
8832 | list_add_tail(&dmabuf->list, &dma_buffer_list); | ||
8833 | } | ||
8834 | while (offset < fw->size) { | ||
8835 | temp_offset = offset; | ||
8836 | list_for_each_entry(dmabuf, &dma_buffer_list, list) { | ||
8837 | if (offset + SLI4_PAGE_SIZE > fw->size) { | ||
8838 | temp_offset += fw->size - offset; | ||
8839 | memcpy(dmabuf->virt, | ||
8840 | fw->data + temp_offset, | ||
8841 | fw->size - offset); | ||
8842 | break; | ||
8843 | } | ||
8844 | temp_offset += SLI4_PAGE_SIZE; | ||
8845 | memcpy(dmabuf->virt, fw->data + temp_offset, | ||
8846 | SLI4_PAGE_SIZE); | ||
8847 | } | ||
8848 | rc = lpfc_wr_object(phba, &dma_buffer_list, | ||
8849 | (fw->size - offset), &offset); | ||
8850 | if (rc) { | ||
8851 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8852 | "3024 Firmware update failed. " | ||
8853 | "%d\n", rc); | ||
8854 | goto out; | ||
8855 | } | ||
8856 | } | ||
8857 | rc = offset; | ||
8858 | } | ||
8859 | out: | ||
8860 | list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { | ||
8861 | list_del(&dmabuf->list); | ||
8862 | dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, | ||
8863 | dmabuf->virt, dmabuf->phys); | ||
8864 | kfree(dmabuf); | ||
8865 | } | ||
8866 | return rc; | ||
8867 | } | ||
8868 | |||
8869 | /** | ||
8778 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys | 8870 | * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys |
8779 | * @pdev: pointer to PCI device | 8871 | * @pdev: pointer to PCI device |
8780 | * @pid: pointer to PCI device identifier | 8872 | * @pid: pointer to PCI device identifier |
@@ -8803,6 +8895,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
8803 | int mcnt; | 8895 | int mcnt; |
8804 | int adjusted_fcp_eq_count; | 8896 | int adjusted_fcp_eq_count; |
8805 | int fcp_qidx; | 8897 | int fcp_qidx; |
8898 | const struct firmware *fw; | ||
8899 | uint8_t file_name[16]; | ||
8806 | 8900 | ||
8807 | /* Allocate memory for HBA structure */ | 8901 | /* Allocate memory for HBA structure */ |
8808 | phba = lpfc_hba_alloc(pdev); | 8902 | phba = lpfc_hba_alloc(pdev); |
@@ -8957,6 +9051,14 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
8957 | /* Perform post initialization setup */ | 9051 | /* Perform post initialization setup */ |
8958 | lpfc_post_init_setup(phba); | 9052 | lpfc_post_init_setup(phba); |
8959 | 9053 | ||
9054 | /* check for firmware upgrade or downgrade */ | ||
9055 | snprintf(file_name, 16, "%s.grp", phba->ModelName); | ||
9056 | error = request_firmware(&fw, file_name, &phba->pcidev->dev); | ||
9057 | if (!error) { | ||
9058 | lpfc_write_firmware(phba, fw); | ||
9059 | release_firmware(fw); | ||
9060 | } | ||
9061 | |||
8960 | /* Check if there are static vports to be created. */ | 9062 | /* Check if there are static vports to be created. */ |
8961 | lpfc_create_static_vport(phba); | 9063 | lpfc_create_static_vport(phba); |
8962 | 9064 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dd911d6d0ee5..fcfa8c8cfb67 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -13500,6 +13500,96 @@ out: | |||
13500 | } | 13500 | } |
13501 | 13501 | ||
13502 | /** | 13502 | /** |
13503 | * lpfc_wr_object - write an object to the firmware | ||
13504 | * @phba: HBA structure that indicates port to create a queue on. | ||
13505 | * @dmabuf_list: list of dmabufs to write to the port. | ||
13506 | * @size: the total byte value of the objects to write to the port. | ||
13507 | * @offset: the current offset to be used to start the transfer. | ||
13508 | * | ||
13509 | * This routine will create a wr_object mailbox command to send to the port. | ||
13510 | * the mailbox command will be constructed using the dma buffers described in | ||
13511 | * @dmabuf_list to create a list of BDEs. This routine will fill in as many | ||
13512 | * BDEs that the imbedded mailbox can support. The @offset variable will be | ||
13513 | * used to indicate the starting offset of the transfer and will also return | ||
13514 | * the offset after the write object mailbox has completed. @size is used to | ||
13515 | * determine the end of the object and whether the eof bit should be set. | ||
13516 | * | ||
13517 | * Return 0 is successful and offset will contain the the new offset to use | ||
13518 | * for the next write. | ||
13519 | * Return negative value for error cases. | ||
13520 | **/ | ||
13521 | int | ||
13522 | lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, | ||
13523 | uint32_t size, uint32_t *offset) | ||
13524 | { | ||
13525 | struct lpfc_mbx_wr_object *wr_object; | ||
13526 | LPFC_MBOXQ_t *mbox; | ||
13527 | int rc = 0, i = 0; | ||
13528 | uint32_t shdr_status, shdr_add_status; | ||
13529 | uint32_t mbox_tmo; | ||
13530 | union lpfc_sli4_cfg_shdr *shdr; | ||
13531 | struct lpfc_dmabuf *dmabuf; | ||
13532 | uint32_t written = 0; | ||
13533 | |||
13534 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
13535 | if (!mbox) | ||
13536 | return -ENOMEM; | ||
13537 | |||
13538 | lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, | ||
13539 | LPFC_MBOX_OPCODE_WRITE_OBJECT, | ||
13540 | sizeof(struct lpfc_mbx_wr_object) - | ||
13541 | sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED); | ||
13542 | |||
13543 | wr_object = (struct lpfc_mbx_wr_object *)&mbox->u.mqe.un.wr_object; | ||
13544 | wr_object->u.request.write_offset = *offset; | ||
13545 | sprintf((uint8_t *)wr_object->u.request.object_name, "/"); | ||
13546 | wr_object->u.request.object_name[0] = | ||
13547 | cpu_to_le32(wr_object->u.request.object_name[0]); | ||
13548 | bf_set(lpfc_wr_object_eof, &wr_object->u.request, 0); | ||
13549 | list_for_each_entry(dmabuf, dmabuf_list, list) { | ||
13550 | if (i >= LPFC_MBX_WR_CONFIG_MAX_BDE || written >= size) | ||
13551 | break; | ||
13552 | wr_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys); | ||
13553 | wr_object->u.request.bde[i].addrHigh = | ||
13554 | putPaddrHigh(dmabuf->phys); | ||
13555 | if (written + SLI4_PAGE_SIZE >= size) { | ||
13556 | wr_object->u.request.bde[i].tus.f.bdeSize = | ||
13557 | (size - written); | ||
13558 | written += (size - written); | ||
13559 | bf_set(lpfc_wr_object_eof, &wr_object->u.request, 1); | ||
13560 | } else { | ||
13561 | wr_object->u.request.bde[i].tus.f.bdeSize = | ||
13562 | SLI4_PAGE_SIZE; | ||
13563 | written += SLI4_PAGE_SIZE; | ||
13564 | } | ||
13565 | i++; | ||
13566 | } | ||
13567 | wr_object->u.request.bde_count = i; | ||
13568 | bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written); | ||
13569 | if (!phba->sli4_hba.intr_enable) | ||
13570 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); | ||
13571 | else { | ||
13572 | mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); | ||
13573 | rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); | ||
13574 | } | ||
13575 | /* The IOCTL status is embedded in the mailbox subheader. */ | ||
13576 | shdr = (union lpfc_sli4_cfg_shdr *) &wr_object->header.cfg_shdr; | ||
13577 | shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); | ||
13578 | shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); | ||
13579 | if (rc != MBX_TIMEOUT) | ||
13580 | mempool_free(mbox, phba->mbox_mem_pool); | ||
13581 | if (shdr_status || shdr_add_status || rc) { | ||
13582 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
13583 | "3025 Write Object mailbox failed with " | ||
13584 | "status x%x add_status x%x, mbx status x%x\n", | ||
13585 | shdr_status, shdr_add_status, rc); | ||
13586 | rc = -ENXIO; | ||
13587 | } else | ||
13588 | *offset += wr_object->u.response.actual_write_length; | ||
13589 | return rc; | ||
13590 | } | ||
13591 | |||
13592 | /** | ||
13503 | * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands. | 13593 | * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands. |
13504 | * @vport: pointer to vport data structure. | 13594 | * @vport: pointer to vport data structure. |
13505 | * | 13595 | * |