isci: Move firmware loading to per PCI device
authorDave Jiang <dave.jiang@intel.com>
Tue, 22 Feb 2011 09:27:03 +0000 (01:27 -0800)
committerDan Williams <dan.j.williams@intel.com>
Sun, 3 Jul 2011 10:55:27 +0000 (03:55 -0700)
Moved the firmware loading from per adapter to per PCI device. This should
prevent firmware from being loaded twice becuase of 2 SCU controller per
PCI device. We do have to do it per PCI device because request_firmware()
requires a struct device passed in.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/scsi/isci/host.c
drivers/scsi/isci/init.c
drivers/scsi/isci/isci.h

index cb2e3f9558e95d6f5f87c023e1cb5c171693022c..aa86615fa7a99ec2c7f93729d7fc69532361bd27 100644 (file)
@@ -354,67 +354,6 @@ void isci_host_deinit(struct isci_host *ihost)
        scic_controller_reset(scic);
 }
 
-static int isci_verify_firmware(const struct firmware *fw,
-                               struct isci_firmware *isci_fw)
-{
-       const u8 *tmp;
-
-       if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
-               return -EINVAL;
-
-       tmp = fw->data;
-
-       /* 12th char should be the NULL terminate for the ID string */
-       if (tmp[11] != '\0')
-               return -EINVAL;
-
-       if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
-               return -EINVAL;
-
-       isci_fw->id = tmp;
-       isci_fw->version = fw->data[ISCI_FW_VER_OFS];
-       isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
-
-       tmp = fw->data + ISCI_FW_DATA_OFS;
-
-       while (*tmp != ISCI_FW_HDR_EOF) {
-               switch (*tmp) {
-               case ISCI_FW_HDR_PHYMASK:
-                       tmp++;
-                       isci_fw->phy_masks_size = *tmp;
-                       tmp++;
-                       isci_fw->phy_masks = (const u32 *)tmp;
-                       tmp += sizeof(u32) * isci_fw->phy_masks_size;
-                       break;
-
-               case ISCI_FW_HDR_PHYGEN:
-                       tmp++;
-                       isci_fw->phy_gens_size = *tmp;
-                       tmp++;
-                       isci_fw->phy_gens = (const u32 *)tmp;
-                       tmp += sizeof(u32) * isci_fw->phy_gens_size;
-                       break;
-
-               case ISCI_FW_HDR_SASADDR:
-                       tmp++;
-                       isci_fw->sas_addrs_size = *tmp;
-                       tmp++;
-                       isci_fw->sas_addrs = (const u64 *)tmp;
-                       tmp += sizeof(u64) * isci_fw->sas_addrs_size;
-                       break;
-
-               default:
-                       pr_err("bad field in firmware binary blob\n");
-                       return -EINVAL;
-               }
-       }
-
-       pr_info("isci firmware v%u.%u loaded.\n",
-              isci_fw->version, isci_fw->subversion);
-
-       return SCI_SUCCESS;
-}
-
 static void __iomem *scu_base(struct isci_host *isci_host)
 {
        struct pci_dev *pdev = isci_host->pdev;
@@ -442,8 +381,6 @@ int isci_host_init(struct isci_host *isci_host)
        struct scic_sds_port *scic_port;
        union scic_oem_parameters scic_oem_params;
        union scic_user_parameters scic_user_params;
-       const struct firmware *fw = NULL;
-       struct isci_firmware *isci_fw = NULL;
 
        INIT_LIST_HEAD(&isci_host->timer_list_struct.timers);
        isci_timer_list_construct(
@@ -454,9 +391,11 @@ int isci_host_init(struct isci_host *isci_host)
        controller = scic_controller_alloc(&isci_host->pdev->dev);
 
        if (!controller) {
-               err = -ENOMEM;
-               dev_err(&isci_host->pdev->dev, "%s: failed (%d)\n", __func__, err);
-               goto out;
+               dev_err(&isci_host->pdev->dev,
+                       "%s: failed (%d)\n",
+                       __func__,
+                       err);
+               return -ENOMEM;
        }
 
        isci_host->core_controller = controller;
@@ -476,8 +415,7 @@ int isci_host_init(struct isci_host *isci_host)
                        "%s: scic_controller_construct failed - status = %x\n",
                        __func__,
                        status);
-               err = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        isci_host->sas_ha.dev = &isci_host->pdev->dev;
@@ -487,93 +425,52 @@ int isci_host_init(struct isci_host *isci_host)
         * set association host adapter struct in core controller.
         */
        sci_object_set_association(isci_host->core_controller,
-                                  (void *)isci_host
-                                  );
+                                  (void *)isci_host);
 
        /* grab initial values stored in the controller object for OEM and USER
         * parameters */
        scic_oem_parameters_get(controller, &scic_oem_params);
        scic_user_parameters_get(controller, &scic_user_params);
 
-       isci_fw = devm_kzalloc(&isci_host->pdev->dev,
-                              sizeof(struct isci_firmware),
-                              GFP_KERNEL);
-       if (!isci_fw) {
-               dev_warn(&isci_host->pdev->dev,
-                        "allocating firmware struct failed\n");
-               dev_warn(&isci_host->pdev->dev,
-                        "Default OEM configuration being used:"
-                        " 4 narrow ports, and default SAS Addresses\n");
-               goto set_default_params;
-       }
-
-       status = request_firmware(&fw, ISCI_FW_NAME, &isci_host->pdev->dev);
-       if (status) {
-               dev_warn(&isci_host->pdev->dev,
-                        "Loading firmware failed, using default values\n");
-               dev_warn(&isci_host->pdev->dev,
-                        "Default OEM configuration being used:"
-                        " 4 narrow ports, and default SAS Addresses\n");
-               goto set_default_params;
-       }
-       else {
-               status = isci_verify_firmware(fw, isci_fw);
-               if (status != SCI_SUCCESS) {
-                       dev_warn(&isci_host->pdev->dev,
-                                "firmware verification failed\n");
-                       dev_warn(&isci_host->pdev->dev,
-                                "Default OEM configuration being used:"
-                                " 4 narrow ports, and default SAS "
-                                "Addresses\n");
-                       goto set_default_params;
-               }
-
-               /* grab any OEM and USER parameters specified at module load */
+       if (isci_firmware) {
+               /* grab any OEM and USER parameters specified in binary blob */
                status = isci_parse_oem_parameters(&scic_oem_params,
-                                                  isci_host->id, isci_fw);
+                                                  isci_host->id,
+                                                  isci_firmware);
                if (status != SCI_SUCCESS) {
                        dev_warn(&isci_host->pdev->dev,
                                 "parsing firmware oem parameters failed\n");
-                       err = -EINVAL;
-                       goto out;
+                       return -EINVAL;
                }
 
                status = isci_parse_user_parameters(&scic_user_params,
-                                                   isci_host->id, isci_fw);
+                                                   isci_host->id,
+                                                   isci_firmware);
                if (status != SCI_SUCCESS) {
                        dev_warn(&isci_host->pdev->dev,
                                 "%s: isci_parse_user_parameters"
                                 " failed\n", __func__);
-                       err = -EINVAL;
-                       goto out;
+                       return -EINVAL;
+               }
+       } else {
+               status = scic_oem_parameters_set(isci_host->core_controller,
+                                                &scic_oem_params);
+               if (status != SCI_SUCCESS) {
+                       dev_warn(&isci_host->pdev->dev,
+                                "%s: scic_oem_parameters_set failed\n",
+                                __func__);
+                       return -ENODEV;
                }
-       }
-
- set_default_params:
-
-       status = scic_oem_parameters_set(isci_host->core_controller,
-                                        &scic_oem_params
-                                        );
-
-       if (status != SCI_SUCCESS) {
-               dev_warn(&isci_host->pdev->dev,
-                        "%s: scic_oem_parameters_set failed\n",
-                        __func__);
-               err = -ENODEV;
-               goto out;
-       }
-
 
-       status = scic_user_parameters_set(isci_host->core_controller,
-                                         &scic_user_params
-                                         );
 
-       if (status != SCI_SUCCESS) {
-               dev_warn(&isci_host->pdev->dev,
-                        "%s: scic_user_parameters_set failed\n",
-                        __func__);
-               err = -ENODEV;
-               goto out;
+               status = scic_user_parameters_set(isci_host->core_controller,
+                                                 &scic_user_params);
+               if (status != SCI_SUCCESS) {
+                       dev_warn(&isci_host->pdev->dev,
+                                "%s: scic_user_parameters_set failed\n",
+                                __func__);
+                       return -ENODEV;
+               }
        }
 
        status = scic_controller_initialize(isci_host->core_controller);
@@ -582,8 +479,7 @@ int isci_host_init(struct isci_host *isci_host)
                         "%s: scic_controller_initialize failed -"
                         " status = 0x%x\n",
                         __func__, status);
-               err = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        tasklet_init(&isci_host->completion_tasklet,
@@ -598,7 +494,7 @@ int isci_host_init(struct isci_host *isci_host)
        err = isci_host_mdl_allocate_coherent(isci_host);
 
        if (err)
-               goto err_out;
+               return err;
 
        /*
         * keep the pool alloc size around, will use it for a bounds checking
@@ -610,40 +506,27 @@ int isci_host_init(struct isci_host *isci_host)
                                               isci_host->dma_pool_alloc_size,
                                               SLAB_HWCACHE_ALIGN, 0);
 
-       if (!isci_host->dma_pool) {
-               err = -ENOMEM;
-               goto req_obj_err_out;
-       }
+       if (!isci_host->dma_pool)
+               return -ENOMEM;
 
-       for (index = 0; index < SCI_MAX_PORTS; index++) {
+       for (index = 0; index < SCI_MAX_PORTS; index++)
                isci_port_init(&isci_host->isci_ports[index],
-                              isci_host, index);
-       }
+                              isci_host,
+                              index);
 
        for (index = 0; index < SCI_MAX_PHYS; index++)
                isci_phy_init(&isci_host->phys[index], isci_host, index);
 
        /* Why are we doing this? Is this even necessary? */
-       memcpy(&isci_host->sas_addr[0], &isci_host->phys[0].sas_addr[0],
+       memcpy(&isci_host->sas_addr[0],
+              &isci_host->phys[0].sas_addr[0],
               SAS_ADDR_SIZE);
 
        /* Start the ports */
        for (index = 0; index < SCI_MAX_PORTS; index++) {
-
                scic_controller_get_port_handle(controller, index, &scic_port);
                scic_port_start(scic_port);
        }
 
-       goto out;
-
-/* SPB_Debug: destroy request object cache */
- req_obj_err_out:
-/* SPB_Debug: destroy remote object cache */
- err_out:
-/* SPB_Debug: undo controller init, construct and alloc, remove from parent
- * controller list. */
- out:
-       if (fw)
-               release_firmware(fw);
-       return err;
+       return 0;
 }
index fda26292ba2b426322b87676b84a2427f1ff2405..6ca623aff05168984f358bab6848f1c83e1f967f 100644 (file)
@@ -82,6 +82,8 @@ static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
        {}
 };
 
+struct isci_firmware *isci_firmware;
+
 static int __devinit isci_pci_probe(
        struct pci_dev *pdev,
        const struct pci_device_id *device_id_p);
@@ -519,11 +521,73 @@ static void check_si_rev(struct pci_dev *pdev)
                
 }
 
+static int isci_verify_firmware(const struct firmware *fw,
+                               struct isci_firmware *isci_fw)
+{
+       const u8 *tmp;
+
+       if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
+               return -EINVAL;
+
+       tmp = fw->data;
+
+       /* 12th char should be the NULL terminate for the ID string */
+       if (tmp[11] != '\0')
+               return -EINVAL;
+
+       if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
+               return -EINVAL;
+
+       isci_fw->id = tmp;
+       isci_fw->version = fw->data[ISCI_FW_VER_OFS];
+       isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
+
+       tmp = fw->data + ISCI_FW_DATA_OFS;
+
+       while (*tmp != ISCI_FW_HDR_EOF) {
+               switch (*tmp) {
+               case ISCI_FW_HDR_PHYMASK:
+                       tmp++;
+                       isci_fw->phy_masks_size = *tmp;
+                       tmp++;
+                       isci_fw->phy_masks = (const u32 *)tmp;
+                       tmp += sizeof(u32) * isci_fw->phy_masks_size;
+                       break;
+
+               case ISCI_FW_HDR_PHYGEN:
+                       tmp++;
+                       isci_fw->phy_gens_size = *tmp;
+                       tmp++;
+                       isci_fw->phy_gens = (const u32 *)tmp;
+                       tmp += sizeof(u32) * isci_fw->phy_gens_size;
+                       break;
+
+               case ISCI_FW_HDR_SASADDR:
+                       tmp++;
+                       isci_fw->sas_addrs_size = *tmp;
+                       tmp++;
+                       isci_fw->sas_addrs = (const u64 *)tmp;
+                       tmp += sizeof(u64) * isci_fw->sas_addrs_size;
+                       break;
+
+               default:
+                       pr_err("bad field in firmware binary blob\n");
+                       return -EINVAL;
+               }
+       }
+
+       pr_info("isci firmware v%u.%u loaded.\n",
+              isci_fw->version, isci_fw->subversion);
+
+       return SCI_SUCCESS;
+}
+
 static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct isci_pci_info *pci_info;
        int err, i;
        struct isci_host *isci_host;
+       const struct firmware *fw = NULL;
 
        check_si_rev(pdev);
 
@@ -532,6 +596,33 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
                return -ENOMEM;
        pci_set_drvdata(pdev, pci_info);
 
+       err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev);
+       if (err) {
+               dev_warn(&pdev->dev,
+                        "Loading firmware failed, using default values\n");
+               dev_warn(&pdev->dev,
+                        "Default OEM configuration being used:"
+                        " 4 narrow ports, and default SAS Addresses\n");
+       } else {
+               isci_firmware = devm_kzalloc(&pdev->dev,
+                                            sizeof(struct isci_firmware),
+                                            GFP_KERNEL);
+               if (isci_firmware) {
+                       err = isci_verify_firmware(fw, isci_firmware);
+                       if (err != SCI_SUCCESS) {
+                               dev_warn(&pdev->dev,
+                                        "firmware verification failed\n");
+                               dev_warn(&pdev->dev,
+                                        "Default OEM configuration being used:"
+                                        " 4 narrow ports, and default SAS "
+                                        "Addresses\n");
+                               devm_kfree(&pdev->dev, isci_firmware);
+                               isci_firmware = NULL;
+                       }
+               }
+               release_firmware(fw);
+       }
+
        err = isci_pci_init(pdev);
        if (err)
                return err;
index 39efd5f272007d63e8c2d78105a0b6be87451f8d..6c79b29f31021f609872e63c3f60a578591a961c 100644 (file)
@@ -86,6 +86,7 @@
 #include "sci_status.h"
 
 extern struct kmem_cache *isci_kmem_cache;
+extern struct isci_firmware *isci_firmware;
 
 #define ISCI_FW_NAME           "isci/isci_firmware.bin"