Commit 52d5244096017bbd11164479116baceaede342b0

Authored by James Smart
Committed by James Bottomley
1 parent 912e3acde6

[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>

Showing 5 changed files with 259 additions and 11 deletions Side-by-side Diff

drivers/scsi/lpfc/lpfc_attr.c
... ... @@ -755,18 +755,18 @@
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 759 * @phba: lpfc_hba pointer.
760 760 *
761 761 * Description:
762   - * Request SLI4 interface type-2 device to perform a dump of firmware dump
763   - * object into it's /dbg directory of the flash file system.
  762 + * Request SLI4 interface type-2 device to perform a physical register set
  763 + * access.
764 764 *
765 765 * Returns:
766 766 * zero for success
767 767 **/
768 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 771 struct completion online_compl;
772 772 uint32_t reg_val;
... ... @@ -776,6 +776,11 @@
776 776 if (!phba->cfg_enable_hba_reset)
777 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 784 status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
780 785  
781 786 if (status != 0)
... ... @@ -786,7 +791,14 @@
786 791  
787 792 reg_val = readl(phba->sli4_hba.conf_regs_memmap_p +
788 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 802 writel(reg_val, phba->sli4_hba.conf_regs_memmap_p +
791 803 LPFC_CTL_PDEV_CTL_OFFSET);
792 804 /* flush */
... ... @@ -904,12 +916,11 @@
904 916 else
905 917 status = lpfc_do_offline(phba, LPFC_EVT_KILL);
906 918 else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0)
907   - if ((phba->sli_rev < LPFC_SLI_REV4) ||
908   - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
909   - LPFC_SLI_INTF_IF_TYPE_2))
910   - return -EPERM;
911   - else
912   - status = lpfc_sli4_fw_dump_request(phba);
  919 + status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP);
  920 + else if (strncmp(buf, "fw_reset", sizeof("fw_reset") - 1) == 0)
  921 + status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET);
  922 + else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0)
  923 + status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET);
913 924 else
914 925 return -EINVAL;
915 926  
drivers/scsi/lpfc/lpfc_crtn.h
... ... @@ -430,6 +430,7 @@
430 430 void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
431 431 struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
432 432 uint32_t);
  433 +int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);
433 434 /* functions to support SR-IOV */
434 435 int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
drivers/scsi/lpfc/lpfc_hw4.h
... ... @@ -821,6 +821,7 @@
821 821 #define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A
822 822 #define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0
823 823 #define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4
  824 +#define LPFC_MBOX_OPCODE_WRITE_OBJECT 0xAC
824 825 #define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5
825 826  
826 827 /* FCoE Opcodes */
... ... @@ -2372,6 +2373,29 @@
2372 2373 #define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4
2373 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 2399 /* mailbox queue entry structure */
2376 2400 struct lpfc_mqe {
2377 2401 uint32_t word0;
... ... @@ -2421,6 +2445,7 @@
2421 2445 struct lpfc_mbx_get_func_cfg get_func_cfg;
2422 2446 struct lpfc_mbx_get_prof_cfg get_prof_cfg;
2423 2447 struct lpfc_mbx_nop nop;
  2448 + struct lpfc_mbx_wr_object wr_object;
2424 2449 } un;
2425 2450 };
2426 2451  
2427 2452  
... ... @@ -2966,9 +2991,29 @@
2966 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 3010 #define FCP_COMMAND 0x0
2970 3011 #define FCP_COMMAND_DATA_OUT 0x1
2971 3012 #define ELS_COMMAND_NON_FIP 0xC
2972 3013 #define ELS_COMMAND_FIP 0xD
2973 3014 #define OTHER_COMMAND 0x8
  3015 +
  3016 +#define LPFC_FW_DUMP 1
  3017 +#define LPFC_FW_RESET 2
  3018 +#define LPFC_DV_RESET 3
drivers/scsi/lpfc/lpfc_init.c
... ... @@ -30,6 +30,7 @@
30 30 #include <linux/ctype.h>
31 31 #include <linux/aer.h>
32 32 #include <linux/slab.h>
  33 +#include <linux/firmware.h>
33 34  
34 35 #include <scsi/scsi.h>
35 36 #include <scsi/scsi_device.h>
... ... @@ -8775,6 +8776,97 @@
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 8870 * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys
8779 8871 * @pdev: pointer to PCI device
8780 8872 * @pid: pointer to PCI device identifier
... ... @@ -8803,6 +8895,8 @@
8803 8895 int mcnt;
8804 8896 int adjusted_fcp_eq_count;
8805 8897 int fcp_qidx;
  8898 + const struct firmware *fw;
  8899 + uint8_t file_name[16];
8806 8900  
8807 8901 /* Allocate memory for HBA structure */
8808 8902 phba = lpfc_hba_alloc(pdev);
... ... @@ -8956,6 +9050,14 @@
8956 9050  
8957 9051 /* Perform post initialization setup */
8958 9052 lpfc_post_init_setup(phba);
  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 + }
8959 9061  
8960 9062 /* Check if there are static vports to be created. */
8961 9063 lpfc_create_static_vport(phba);
drivers/scsi/lpfc/lpfc_sli.c
... ... @@ -13500,6 +13500,96 @@
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 13593 * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands.
13504 13594 * @vport: pointer to vport data structure.
13505 13595 *