diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/isci/init.c | 7 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.c | 48 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.h | 13 |
3 files changed, 60 insertions, 8 deletions
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 13105294fbea..ef0c49a0c0a0 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -495,8 +495,11 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic } if (orom) - dev_info(&pdev->dev, "sas parameters (version: %#x) loaded\n", - orom->hdr.version); + dev_info(&pdev->dev, + "OEM SAS parameters (version: %u.%u) loaded\n", + (orom->hdr.version & 0xf0) >> 4, + (orom->hdr.version & 0xf)); + pci_info->orom = orom; err = isci_pci_init(pdev); diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index 822240578115..64e9a808c814 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -51,6 +51,10 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) void __iomem *oprom = pci_map_biosrom(pdev); struct isci_orom *rom = NULL; size_t len, i; + int j; + char oem_sig[4]; + struct isci_oem_hdr oem_hdr; + u8 *tmp, sum; if (!oprom) return NULL; @@ -58,13 +62,45 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) len = pci_biosrom_size(pdev); rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); - for (i = 0; i < len && rom; i += ISCI_ROM_SIG_SIZE) { - memcpy_fromio(rom->hdr.signature, oprom + i, ISCI_ROM_SIG_SIZE); - if (memcmp(rom->hdr.signature, ISCI_ROM_SIG, - ISCI_ROM_SIG_SIZE) == 0) { - size_t copy_len = min(len - i, sizeof(*rom)); + for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) { + memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE); - memcpy_fromio(rom, oprom + i, copy_len); + /* we think we found the OEM table */ + if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) { + size_t copy_len; + + memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr)); + + copy_len = min(oem_hdr.len - sizeof(oem_hdr), + sizeof(*rom)); + + memcpy_fromio(rom, + oprom + i + sizeof(oem_hdr), + copy_len); + + /* calculate checksum */ + tmp = (u8 *)&oem_hdr; + for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) + sum += *tmp; + + tmp = (u8 *)rom; + for (j = 0; j < sizeof(*rom); j++, tmp++) + sum += *tmp; + + if (sum != 0) { + dev_warn(&pdev->dev, + "OEM table checksum failed\n"); + continue; + } + + /* keep going if that's not the oem param table */ + if (memcmp(rom->hdr.signature, + ISCI_ROM_SIG, + ISCI_ROM_SIG_SIZE) != 0) + continue; + + dev_info(&pdev->dev, + "OEM parameter table found in OROM\n"); break; } } diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index 02940e709f97..0449239dae45 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h @@ -70,6 +70,17 @@ enum sci_status isci_parse_oem_parameters( int scu_index); struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); + +struct isci_oem_hdr { + u8 sig[4]; + u8 rev_major; + u8 rev_minor; + u16 len; + u8 checksum; + u8 reserved1; + u16 reserved2; +} __attribute__ ((packed)); + #else #define SCI_MAX_PORTS 4 #define SCI_MAX_PHYS 4 @@ -80,6 +91,8 @@ struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); #define ROMSIGNATURE 0xaa55 +#define ISCI_OEM_SIG "$OEM" +#define ISCI_OEM_SIG_SIZE 4 #define ISCI_ROM_SIG "ISCUOEMB" #define ISCI_ROM_SIG_SIZE 8 |