diff options
author | Dave Jiang <dave.jiang@intel.com> | 2011-02-22 04:27:03 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 06:55:27 -0400 |
commit | 858d4aa741c80fb7579cda3517853f0cffc73772 (patch) | |
tree | db0bc07852d91c5817315d37a8e5923898192d52 /drivers/scsi/isci/init.c | |
parent | 92cd51153d5c18af027ddf42547d59ba4167873c (diff) |
isci: Move firmware loading to per PCI device
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>
Diffstat (limited to 'drivers/scsi/isci/init.c')
-rw-r--r-- | drivers/scsi/isci/init.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index fda26292ba2b..6ca623aff051 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
@@ -82,6 +82,8 @@ static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { | |||
82 | {} | 82 | {} |
83 | }; | 83 | }; |
84 | 84 | ||
85 | struct isci_firmware *isci_firmware; | ||
86 | |||
85 | static int __devinit isci_pci_probe( | 87 | static int __devinit isci_pci_probe( |
86 | struct pci_dev *pdev, | 88 | struct pci_dev *pdev, |
87 | const struct pci_device_id *device_id_p); | 89 | const struct pci_device_id *device_id_p); |
@@ -519,11 +521,73 @@ static void check_si_rev(struct pci_dev *pdev) | |||
519 | 521 | ||
520 | } | 522 | } |
521 | 523 | ||
524 | static int isci_verify_firmware(const struct firmware *fw, | ||
525 | struct isci_firmware *isci_fw) | ||
526 | { | ||
527 | const u8 *tmp; | ||
528 | |||
529 | if (fw->size < ISCI_FIRMWARE_MIN_SIZE) | ||
530 | return -EINVAL; | ||
531 | |||
532 | tmp = fw->data; | ||
533 | |||
534 | /* 12th char should be the NULL terminate for the ID string */ | ||
535 | if (tmp[11] != '\0') | ||
536 | return -EINVAL; | ||
537 | |||
538 | if (strncmp("#SCU MAGIC#", tmp, 11) != 0) | ||
539 | return -EINVAL; | ||
540 | |||
541 | isci_fw->id = tmp; | ||
542 | isci_fw->version = fw->data[ISCI_FW_VER_OFS]; | ||
543 | isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS]; | ||
544 | |||
545 | tmp = fw->data + ISCI_FW_DATA_OFS; | ||
546 | |||
547 | while (*tmp != ISCI_FW_HDR_EOF) { | ||
548 | switch (*tmp) { | ||
549 | case ISCI_FW_HDR_PHYMASK: | ||
550 | tmp++; | ||
551 | isci_fw->phy_masks_size = *tmp; | ||
552 | tmp++; | ||
553 | isci_fw->phy_masks = (const u32 *)tmp; | ||
554 | tmp += sizeof(u32) * isci_fw->phy_masks_size; | ||
555 | break; | ||
556 | |||
557 | case ISCI_FW_HDR_PHYGEN: | ||
558 | tmp++; | ||
559 | isci_fw->phy_gens_size = *tmp; | ||
560 | tmp++; | ||
561 | isci_fw->phy_gens = (const u32 *)tmp; | ||
562 | tmp += sizeof(u32) * isci_fw->phy_gens_size; | ||
563 | break; | ||
564 | |||
565 | case ISCI_FW_HDR_SASADDR: | ||
566 | tmp++; | ||
567 | isci_fw->sas_addrs_size = *tmp; | ||
568 | tmp++; | ||
569 | isci_fw->sas_addrs = (const u64 *)tmp; | ||
570 | tmp += sizeof(u64) * isci_fw->sas_addrs_size; | ||
571 | break; | ||
572 | |||
573 | default: | ||
574 | pr_err("bad field in firmware binary blob\n"); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | pr_info("isci firmware v%u.%u loaded.\n", | ||
580 | isci_fw->version, isci_fw->subversion); | ||
581 | |||
582 | return SCI_SUCCESS; | ||
583 | } | ||
584 | |||
522 | static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 585 | static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
523 | { | 586 | { |
524 | struct isci_pci_info *pci_info; | 587 | struct isci_pci_info *pci_info; |
525 | int err, i; | 588 | int err, i; |
526 | struct isci_host *isci_host; | 589 | struct isci_host *isci_host; |
590 | const struct firmware *fw = NULL; | ||
527 | 591 | ||
528 | check_si_rev(pdev); | 592 | check_si_rev(pdev); |
529 | 593 | ||
@@ -532,6 +596,33 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic | |||
532 | return -ENOMEM; | 596 | return -ENOMEM; |
533 | pci_set_drvdata(pdev, pci_info); | 597 | pci_set_drvdata(pdev, pci_info); |
534 | 598 | ||
599 | err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev); | ||
600 | if (err) { | ||
601 | dev_warn(&pdev->dev, | ||
602 | "Loading firmware failed, using default values\n"); | ||
603 | dev_warn(&pdev->dev, | ||
604 | "Default OEM configuration being used:" | ||
605 | " 4 narrow ports, and default SAS Addresses\n"); | ||
606 | } else { | ||
607 | isci_firmware = devm_kzalloc(&pdev->dev, | ||
608 | sizeof(struct isci_firmware), | ||
609 | GFP_KERNEL); | ||
610 | if (isci_firmware) { | ||
611 | err = isci_verify_firmware(fw, isci_firmware); | ||
612 | if (err != SCI_SUCCESS) { | ||
613 | dev_warn(&pdev->dev, | ||
614 | "firmware verification failed\n"); | ||
615 | dev_warn(&pdev->dev, | ||
616 | "Default OEM configuration being used:" | ||
617 | " 4 narrow ports, and default SAS " | ||
618 | "Addresses\n"); | ||
619 | devm_kfree(&pdev->dev, isci_firmware); | ||
620 | isci_firmware = NULL; | ||
621 | } | ||
622 | } | ||
623 | release_firmware(fw); | ||
624 | } | ||
625 | |||
535 | err = isci_pci_init(pdev); | 626 | err = isci_pci_init(pdev); |
536 | if (err) | 627 | if (err) |
537 | return err; | 628 | return err; |