162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Aic94xx SAS/SATA driver initialization. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 662306a36Sopenharmony_ci * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/firmware.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <scsi/scsi_host.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "aic94xx.h" 2062306a36Sopenharmony_ci#include "aic94xx_reg.h" 2162306a36Sopenharmony_ci#include "aic94xx_hwi.h" 2262306a36Sopenharmony_ci#include "aic94xx_seq.h" 2362306a36Sopenharmony_ci#include "aic94xx_sds.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* The format is "version.release.patchlevel" */ 2662306a36Sopenharmony_ci#define ASD_DRIVER_VERSION "1.0.3" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int use_msi = 0; 2962306a36Sopenharmony_cimodule_param_named(use_msi, use_msi, int, S_IRUGO); 3062306a36Sopenharmony_ciMODULE_PARM_DESC(use_msi, "\n" 3162306a36Sopenharmony_ci "\tEnable(1) or disable(0) using PCI MSI.\n" 3262306a36Sopenharmony_ci "\tDefault: 0"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct scsi_transport_template *aic94xx_transport_template; 3562306a36Sopenharmony_cistatic int asd_scan_finished(struct Scsi_Host *, unsigned long); 3662306a36Sopenharmony_cistatic void asd_scan_start(struct Scsi_Host *); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const struct scsi_host_template aic94xx_sht = { 3962306a36Sopenharmony_ci .module = THIS_MODULE, 4062306a36Sopenharmony_ci /* .name is initialized */ 4162306a36Sopenharmony_ci .name = "aic94xx", 4262306a36Sopenharmony_ci .queuecommand = sas_queuecommand, 4362306a36Sopenharmony_ci .dma_need_drain = ata_scsi_dma_need_drain, 4462306a36Sopenharmony_ci .target_alloc = sas_target_alloc, 4562306a36Sopenharmony_ci .slave_configure = sas_slave_configure, 4662306a36Sopenharmony_ci .scan_finished = asd_scan_finished, 4762306a36Sopenharmony_ci .scan_start = asd_scan_start, 4862306a36Sopenharmony_ci .change_queue_depth = sas_change_queue_depth, 4962306a36Sopenharmony_ci .bios_param = sas_bios_param, 5062306a36Sopenharmony_ci .can_queue = 1, 5162306a36Sopenharmony_ci .this_id = -1, 5262306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 5362306a36Sopenharmony_ci .max_sectors = SCSI_DEFAULT_MAX_SECTORS, 5462306a36Sopenharmony_ci .eh_device_reset_handler = sas_eh_device_reset_handler, 5562306a36Sopenharmony_ci .eh_target_reset_handler = sas_eh_target_reset_handler, 5662306a36Sopenharmony_ci .slave_alloc = sas_slave_alloc, 5762306a36Sopenharmony_ci .target_destroy = sas_target_destroy, 5862306a36Sopenharmony_ci .ioctl = sas_ioctl, 5962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 6062306a36Sopenharmony_ci .compat_ioctl = sas_ioctl, 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci .track_queue_depth = 1, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int asd_map_memio(struct asd_ha_struct *asd_ha) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int err, i; 6862306a36Sopenharmony_ci struct asd_ha_addrspace *io_handle; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci asd_ha->iospace = 0; 7162306a36Sopenharmony_ci for (i = 0; i < 3; i += 2) { 7262306a36Sopenharmony_ci io_handle = &asd_ha->io_handle[i==0?0:1]; 7362306a36Sopenharmony_ci io_handle->start = pci_resource_start(asd_ha->pcidev, i); 7462306a36Sopenharmony_ci io_handle->len = pci_resource_len(asd_ha->pcidev, i); 7562306a36Sopenharmony_ci io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); 7662306a36Sopenharmony_ci err = -ENODEV; 7762306a36Sopenharmony_ci if (!io_handle->start || !io_handle->len) { 7862306a36Sopenharmony_ci asd_printk("MBAR%d start or length for %s is 0.\n", 7962306a36Sopenharmony_ci i==0?0:1, pci_name(asd_ha->pcidev)); 8062306a36Sopenharmony_ci goto Err; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); 8362306a36Sopenharmony_ci if (err) { 8462306a36Sopenharmony_ci asd_printk("couldn't reserve memory region for %s\n", 8562306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 8662306a36Sopenharmony_ci goto Err; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci io_handle->addr = ioremap(io_handle->start, io_handle->len); 8962306a36Sopenharmony_ci if (!io_handle->addr) { 9062306a36Sopenharmony_ci asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1, 9162306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 9262306a36Sopenharmony_ci err = -ENOMEM; 9362306a36Sopenharmony_ci goto Err_unreq; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ciErr_unreq: 9962306a36Sopenharmony_ci pci_release_region(asd_ha->pcidev, i); 10062306a36Sopenharmony_ciErr: 10162306a36Sopenharmony_ci if (i > 0) { 10262306a36Sopenharmony_ci io_handle = &asd_ha->io_handle[0]; 10362306a36Sopenharmony_ci iounmap(io_handle->addr); 10462306a36Sopenharmony_ci pci_release_region(asd_ha->pcidev, 0); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci return err; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void asd_unmap_memio(struct asd_ha_struct *asd_ha) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct asd_ha_addrspace *io_handle; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci io_handle = &asd_ha->io_handle[1]; 11462306a36Sopenharmony_ci iounmap(io_handle->addr); 11562306a36Sopenharmony_ci pci_release_region(asd_ha->pcidev, 2); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci io_handle = &asd_ha->io_handle[0]; 11862306a36Sopenharmony_ci iounmap(io_handle->addr); 11962306a36Sopenharmony_ci pci_release_region(asd_ha->pcidev, 0); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int asd_map_ioport(struct asd_ha_struct *asd_ha) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int i = PCI_IOBAR_OFFSET, err; 12562306a36Sopenharmony_ci struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci asd_ha->iospace = 1; 12862306a36Sopenharmony_ci io_handle->start = pci_resource_start(asd_ha->pcidev, i); 12962306a36Sopenharmony_ci io_handle->len = pci_resource_len(asd_ha->pcidev, i); 13062306a36Sopenharmony_ci io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); 13162306a36Sopenharmony_ci io_handle->addr = (void __iomem *) io_handle->start; 13262306a36Sopenharmony_ci if (!io_handle->start || !io_handle->len) { 13362306a36Sopenharmony_ci asd_printk("couldn't get IO ports for %s\n", 13462306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 13562306a36Sopenharmony_ci return -ENODEV; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); 13862306a36Sopenharmony_ci if (err) { 13962306a36Sopenharmony_ci asd_printk("couldn't reserve io space for %s\n", 14062306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return err; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void asd_unmap_ioport(struct asd_ha_struct *asd_ha) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int asd_map_ha(struct asd_ha_struct *asd_ha) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci int err; 15462306a36Sopenharmony_ci u16 cmd_reg; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg); 15762306a36Sopenharmony_ci if (err) { 15862306a36Sopenharmony_ci asd_printk("couldn't read command register of %s\n", 15962306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 16062306a36Sopenharmony_ci goto Err; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci err = -ENODEV; 16462306a36Sopenharmony_ci if (cmd_reg & PCI_COMMAND_MEMORY) { 16562306a36Sopenharmony_ci if ((err = asd_map_memio(asd_ha))) 16662306a36Sopenharmony_ci goto Err; 16762306a36Sopenharmony_ci } else if (cmd_reg & PCI_COMMAND_IO) { 16862306a36Sopenharmony_ci if ((err = asd_map_ioport(asd_ha))) 16962306a36Sopenharmony_ci goto Err; 17062306a36Sopenharmony_ci asd_printk("%s ioport mapped -- upgrade your hardware\n", 17162306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 17262306a36Sopenharmony_ci } else { 17362306a36Sopenharmony_ci asd_printk("no proper device access to %s\n", 17462306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 17562306a36Sopenharmony_ci goto Err; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ciErr: 18062306a36Sopenharmony_ci return err; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void asd_unmap_ha(struct asd_ha_struct *asd_ha) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci if (asd_ha->iospace) 18662306a36Sopenharmony_ci asd_unmap_ioport(asd_ha); 18762306a36Sopenharmony_ci else 18862306a36Sopenharmony_ci asd_unmap_memio(asd_ha); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic const char *asd_dev_rev[30] = { 19262306a36Sopenharmony_ci [0] = "A0", 19362306a36Sopenharmony_ci [1] = "A1", 19462306a36Sopenharmony_ci [8] = "B0", 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int asd_common_setup(struct asd_ha_struct *asd_ha) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci int err, i; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci asd_ha->revision_id = asd_ha->pcidev->revision; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci err = -ENODEV; 20462306a36Sopenharmony_ci if (asd_ha->revision_id < AIC9410_DEV_REV_B0) { 20562306a36Sopenharmony_ci asd_printk("%s is revision %s (%X), which is not supported\n", 20662306a36Sopenharmony_ci pci_name(asd_ha->pcidev), 20762306a36Sopenharmony_ci asd_dev_rev[asd_ha->revision_id], 20862306a36Sopenharmony_ci asd_ha->revision_id); 20962306a36Sopenharmony_ci goto Err; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci /* Provide some sane default values. */ 21262306a36Sopenharmony_ci asd_ha->hw_prof.max_scbs = 512; 21362306a36Sopenharmony_ci asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS; 21462306a36Sopenharmony_ci asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; 21562306a36Sopenharmony_ci /* All phys are enabled, by default. */ 21662306a36Sopenharmony_ci asd_ha->hw_prof.enabled_phys = 0xFF; 21762306a36Sopenharmony_ci for (i = 0; i < ASD_MAX_PHYS; i++) { 21862306a36Sopenharmony_ci asd_ha->hw_prof.phy_desc[i].max_sas_lrate = 21962306a36Sopenharmony_ci SAS_LINK_RATE_3_0_GBPS; 22062306a36Sopenharmony_ci asd_ha->hw_prof.phy_desc[i].min_sas_lrate = 22162306a36Sopenharmony_ci SAS_LINK_RATE_1_5_GBPS; 22262306a36Sopenharmony_ci asd_ha->hw_prof.phy_desc[i].max_sata_lrate = 22362306a36Sopenharmony_ci SAS_LINK_RATE_1_5_GBPS; 22462306a36Sopenharmony_ci asd_ha->hw_prof.phy_desc[i].min_sata_lrate = 22562306a36Sopenharmony_ci SAS_LINK_RATE_1_5_GBPS; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ciErr: 23062306a36Sopenharmony_ci return err; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int asd_aic9410_setup(struct asd_ha_struct *asd_ha) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int err = asd_common_setup(asd_ha); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci asd_ha->hw_prof.addr_range = 8; 24162306a36Sopenharmony_ci asd_ha->hw_prof.port_name_base = 0; 24262306a36Sopenharmony_ci asd_ha->hw_prof.dev_name_base = 8; 24362306a36Sopenharmony_ci asd_ha->hw_prof.sata_name_base = 16; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int asd_aic9405_setup(struct asd_ha_struct *asd_ha) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci int err = asd_common_setup(asd_ha); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (err) 25362306a36Sopenharmony_ci return err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci asd_ha->hw_prof.addr_range = 4; 25662306a36Sopenharmony_ci asd_ha->hw_prof.port_name_base = 0; 25762306a36Sopenharmony_ci asd_ha->hw_prof.dev_name_base = 4; 25862306a36Sopenharmony_ci asd_ha->hw_prof.sata_name_base = 8; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic ssize_t asd_show_dev_rev(struct device *dev, 26462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); 26762306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", 26862306a36Sopenharmony_ci asd_dev_rev[asd_ha->revision_id]); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_cistatic DEVICE_ATTR(aic_revision, S_IRUGO, asd_show_dev_rev, NULL); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic ssize_t asd_show_dev_bios_build(struct device *dev, 27362306a36Sopenharmony_ci struct device_attribute *attr,char *buf) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); 27662306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_cistatic DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic ssize_t asd_show_dev_pcba_sn(struct device *dev, 28162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); 28462306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_cistatic DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define FLASH_CMD_NONE 0x00 28962306a36Sopenharmony_ci#define FLASH_CMD_UPDATE 0x01 29062306a36Sopenharmony_ci#define FLASH_CMD_VERIFY 0x02 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistruct flash_command { 29362306a36Sopenharmony_ci u8 command[8]; 29462306a36Sopenharmony_ci int code; 29562306a36Sopenharmony_ci}; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic struct flash_command flash_command_table[] = 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci {"verify", FLASH_CMD_VERIFY}, 30062306a36Sopenharmony_ci {"update", FLASH_CMD_UPDATE}, 30162306a36Sopenharmony_ci {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistruct error_bios { 30562306a36Sopenharmony_ci char *reason; 30662306a36Sopenharmony_ci int err_code; 30762306a36Sopenharmony_ci}; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic struct error_bios flash_error_table[] = 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE}, 31262306a36Sopenharmony_ci {"PCI ID mismatch", FAIL_CHECK_PCI_ID}, 31362306a36Sopenharmony_ci {"Checksum mismatch", FAIL_CHECK_SUM}, 31462306a36Sopenharmony_ci {"Unknown Error", FAIL_UNKNOWN}, 31562306a36Sopenharmony_ci {"Failed to verify.", FAIL_VERIFY}, 31662306a36Sopenharmony_ci {"Failed to reset flash chip.", FAIL_RESET_FLASH}, 31762306a36Sopenharmony_ci {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID}, 31862306a36Sopenharmony_ci {"Failed to erash flash chip.", FAIL_ERASE_FLASH}, 31962306a36Sopenharmony_ci {"Failed to program flash chip.", FAIL_WRITE_FLASH}, 32062306a36Sopenharmony_ci {"Flash in progress", FLASH_IN_PROGRESS}, 32162306a36Sopenharmony_ci {"Image file size Error", FAIL_FILE_SIZE}, 32262306a36Sopenharmony_ci {"Input parameter error", FAIL_PARAMETERS}, 32362306a36Sopenharmony_ci {"Out of memory", FAIL_OUT_MEMORY}, 32462306a36Sopenharmony_ci {"OK", 0} /* Last entry err_code = 0. */ 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic ssize_t asd_store_update_bios(struct device *dev, 32862306a36Sopenharmony_ci struct device_attribute *attr, 32962306a36Sopenharmony_ci const char *buf, size_t count) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); 33262306a36Sopenharmony_ci char *cmd_ptr, *filename_ptr; 33362306a36Sopenharmony_ci struct bios_file_header header, *hdr_ptr; 33462306a36Sopenharmony_ci int res, i; 33562306a36Sopenharmony_ci u32 csum = 0; 33662306a36Sopenharmony_ci int flash_command = FLASH_CMD_NONE; 33762306a36Sopenharmony_ci int err = 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci cmd_ptr = kcalloc(count, 2, GFP_KERNEL); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!cmd_ptr) { 34262306a36Sopenharmony_ci err = FAIL_OUT_MEMORY; 34362306a36Sopenharmony_ci goto out; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci filename_ptr = cmd_ptr + count; 34762306a36Sopenharmony_ci res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); 34862306a36Sopenharmony_ci if (res != 2) { 34962306a36Sopenharmony_ci err = FAIL_PARAMETERS; 35062306a36Sopenharmony_ci goto out1; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { 35462306a36Sopenharmony_ci if (!memcmp(flash_command_table[i].command, 35562306a36Sopenharmony_ci cmd_ptr, strlen(cmd_ptr))) { 35662306a36Sopenharmony_ci flash_command = flash_command_table[i].code; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci if (flash_command == FLASH_CMD_NONE) { 36162306a36Sopenharmony_ci err = FAIL_PARAMETERS; 36262306a36Sopenharmony_ci goto out1; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (asd_ha->bios_status == FLASH_IN_PROGRESS) { 36662306a36Sopenharmony_ci err = FLASH_IN_PROGRESS; 36762306a36Sopenharmony_ci goto out1; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci err = request_firmware(&asd_ha->bios_image, 37062306a36Sopenharmony_ci filename_ptr, 37162306a36Sopenharmony_ci &asd_ha->pcidev->dev); 37262306a36Sopenharmony_ci if (err) { 37362306a36Sopenharmony_ci asd_printk("Failed to load bios image file %s, error %d\n", 37462306a36Sopenharmony_ci filename_ptr, err); 37562306a36Sopenharmony_ci err = FAIL_OPEN_BIOS_FILE; 37662306a36Sopenharmony_ci goto out1; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor || 38262306a36Sopenharmony_ci hdr_ptr->contrl_id.device != asd_ha->pcidev->device) && 38362306a36Sopenharmony_ci (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor || 38462306a36Sopenharmony_ci hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) { 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ASD_DPRINTK("The PCI vendor or device id does not match\n"); 38762306a36Sopenharmony_ci ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x" 38862306a36Sopenharmony_ci " pci vendor=%x pci dev=%x\n", 38962306a36Sopenharmony_ci hdr_ptr->contrl_id.vendor, 39062306a36Sopenharmony_ci hdr_ptr->contrl_id.device, 39162306a36Sopenharmony_ci hdr_ptr->contrl_id.sub_vendor, 39262306a36Sopenharmony_ci hdr_ptr->contrl_id.sub_device, 39362306a36Sopenharmony_ci asd_ha->pcidev->vendor, 39462306a36Sopenharmony_ci asd_ha->pcidev->device); 39562306a36Sopenharmony_ci err = FAIL_CHECK_PCI_ID; 39662306a36Sopenharmony_ci goto out2; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (hdr_ptr->filelen != asd_ha->bios_image->size) { 40062306a36Sopenharmony_ci err = FAIL_FILE_SIZE; 40162306a36Sopenharmony_ci goto out2; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* calculate checksum */ 40562306a36Sopenharmony_ci for (i = 0; i < hdr_ptr->filelen; i++) 40662306a36Sopenharmony_ci csum += asd_ha->bios_image->data[i]; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if ((csum & 0x0000ffff) != hdr_ptr->checksum) { 40962306a36Sopenharmony_ci ASD_DPRINTK("BIOS file checksum mismatch\n"); 41062306a36Sopenharmony_ci err = FAIL_CHECK_SUM; 41162306a36Sopenharmony_ci goto out2; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci if (flash_command == FLASH_CMD_UPDATE) { 41462306a36Sopenharmony_ci asd_ha->bios_status = FLASH_IN_PROGRESS; 41562306a36Sopenharmony_ci err = asd_write_flash_seg(asd_ha, 41662306a36Sopenharmony_ci &asd_ha->bios_image->data[sizeof(*hdr_ptr)], 41762306a36Sopenharmony_ci 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); 41862306a36Sopenharmony_ci if (!err) 41962306a36Sopenharmony_ci err = asd_verify_flash_seg(asd_ha, 42062306a36Sopenharmony_ci &asd_ha->bios_image->data[sizeof(*hdr_ptr)], 42162306a36Sopenharmony_ci 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci asd_ha->bios_status = FLASH_IN_PROGRESS; 42462306a36Sopenharmony_ci err = asd_verify_flash_seg(asd_ha, 42562306a36Sopenharmony_ci &asd_ha->bios_image->data[sizeof(header)], 42662306a36Sopenharmony_ci 0, hdr_ptr->filelen-sizeof(header)); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciout2: 43062306a36Sopenharmony_ci release_firmware(asd_ha->bios_image); 43162306a36Sopenharmony_ciout1: 43262306a36Sopenharmony_ci kfree(cmd_ptr); 43362306a36Sopenharmony_ciout: 43462306a36Sopenharmony_ci asd_ha->bios_status = err; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!err) 43762306a36Sopenharmony_ci return count; 43862306a36Sopenharmony_ci else 43962306a36Sopenharmony_ci return -err; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic ssize_t asd_show_update_bios(struct device *dev, 44362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci int i; 44662306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (i = 0; flash_error_table[i].err_code != 0; i++) { 44962306a36Sopenharmony_ci if (flash_error_table[i].err_code == asd_ha->bios_status) 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci if (asd_ha->bios_status != FLASH_IN_PROGRESS) 45362306a36Sopenharmony_ci asd_ha->bios_status = FLASH_OK; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "status=%x %s\n", 45662306a36Sopenharmony_ci flash_error_table[i].err_code, 45762306a36Sopenharmony_ci flash_error_table[i].reason); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic DEVICE_ATTR(update_bios, S_IRUGO|S_IWUSR, 46162306a36Sopenharmony_ci asd_show_update_bios, asd_store_update_bios); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci int err; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_aic_revision); 46862306a36Sopenharmony_ci if (err) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); 47262306a36Sopenharmony_ci if (err) 47362306a36Sopenharmony_ci goto err_rev; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); 47662306a36Sopenharmony_ci if (err) 47762306a36Sopenharmony_ci goto err_biosb; 47862306a36Sopenharmony_ci err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); 47962306a36Sopenharmony_ci if (err) 48062306a36Sopenharmony_ci goto err_update_bios; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cierr_update_bios: 48562306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); 48662306a36Sopenharmony_cierr_biosb: 48762306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); 48862306a36Sopenharmony_cierr_rev: 48962306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_aic_revision); 49062306a36Sopenharmony_ci return err; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_aic_revision); 49662306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); 49762306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); 49862306a36Sopenharmony_ci device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* The first entry, 0, is used for dynamic ids, the rest for devices 50262306a36Sopenharmony_ci * we know about. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic const struct asd_pcidev_struct { 50562306a36Sopenharmony_ci const char * name; 50662306a36Sopenharmony_ci int (*setup)(struct asd_ha_struct *asd_ha); 50762306a36Sopenharmony_ci} asd_pcidev_data[] = { 50862306a36Sopenharmony_ci /* Id 0 is used for dynamic ids. */ 50962306a36Sopenharmony_ci { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter", 51062306a36Sopenharmony_ci .setup = asd_aic9410_setup 51162306a36Sopenharmony_ci }, 51262306a36Sopenharmony_ci { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter", 51362306a36Sopenharmony_ci .setup = asd_aic9410_setup 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter", 51662306a36Sopenharmony_ci .setup = asd_aic9405_setup 51762306a36Sopenharmony_ci }, 51862306a36Sopenharmony_ci}; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int asd_create_ha_caches(struct asd_ha_struct *asd_ha) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool", 52362306a36Sopenharmony_ci &asd_ha->pcidev->dev, 52462306a36Sopenharmony_ci sizeof(struct scb), 52562306a36Sopenharmony_ci 8, 0); 52662306a36Sopenharmony_ci if (!asd_ha->scb_pool) { 52762306a36Sopenharmony_ci asd_printk("couldn't create scb pool\n"); 52862306a36Sopenharmony_ci return -ENOMEM; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* 53562306a36Sopenharmony_ci * asd_free_edbs -- free empty data buffers 53662306a36Sopenharmony_ci * asd_ha: pointer to host adapter structure 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_cistatic void asd_free_edbs(struct asd_ha_struct *asd_ha) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct asd_seq_data *seq = &asd_ha->seq; 54162306a36Sopenharmony_ci int i; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci for (i = 0; i < seq->num_edbs; i++) 54462306a36Sopenharmony_ci asd_free_coherent(asd_ha, seq->edb_arr[i]); 54562306a36Sopenharmony_ci kfree(seq->edb_arr); 54662306a36Sopenharmony_ci seq->edb_arr = NULL; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void asd_free_escbs(struct asd_ha_struct *asd_ha) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct asd_seq_data *seq = &asd_ha->seq; 55262306a36Sopenharmony_ci int i; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (i = 0; i < seq->num_escbs; i++) { 55562306a36Sopenharmony_ci if (!list_empty(&seq->escb_arr[i]->list)) 55662306a36Sopenharmony_ci list_del_init(&seq->escb_arr[i]->list); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci asd_ascb_free(seq->escb_arr[i]); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci kfree(seq->escb_arr); 56162306a36Sopenharmony_ci seq->escb_arr = NULL; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci int i; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (asd_ha->hw_prof.ddb_ext) 56962306a36Sopenharmony_ci asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext); 57062306a36Sopenharmony_ci if (asd_ha->hw_prof.scb_ext) 57162306a36Sopenharmony_ci asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci kfree(asd_ha->hw_prof.ddb_bitmap); 57462306a36Sopenharmony_ci asd_ha->hw_prof.ddb_bitmap = NULL; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci for (i = 0; i < ASD_MAX_PHYS; i++) { 57762306a36Sopenharmony_ci struct asd_phy *phy = &asd_ha->phys[i]; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci asd_free_coherent(asd_ha, phy->id_frm_tok); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci if (asd_ha->seq.escb_arr) 58262306a36Sopenharmony_ci asd_free_escbs(asd_ha); 58362306a36Sopenharmony_ci if (asd_ha->seq.edb_arr) 58462306a36Sopenharmony_ci asd_free_edbs(asd_ha); 58562306a36Sopenharmony_ci if (asd_ha->hw_prof.ue.area) { 58662306a36Sopenharmony_ci kfree(asd_ha->hw_prof.ue.area); 58762306a36Sopenharmony_ci asd_ha->hw_prof.ue.area = NULL; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci if (asd_ha->seq.tc_index_array) { 59062306a36Sopenharmony_ci kfree(asd_ha->seq.tc_index_array); 59162306a36Sopenharmony_ci kfree(asd_ha->seq.tc_index_bitmap); 59262306a36Sopenharmony_ci asd_ha->seq.tc_index_array = NULL; 59362306a36Sopenharmony_ci asd_ha->seq.tc_index_bitmap = NULL; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci if (asd_ha->seq.actual_dl) { 59662306a36Sopenharmony_ci asd_free_coherent(asd_ha, asd_ha->seq.actual_dl); 59762306a36Sopenharmony_ci asd_ha->seq.actual_dl = NULL; 59862306a36Sopenharmony_ci asd_ha->seq.dl = NULL; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci if (asd_ha->seq.next_scb.vaddr) { 60162306a36Sopenharmony_ci dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr, 60262306a36Sopenharmony_ci asd_ha->seq.next_scb.dma_handle); 60362306a36Sopenharmony_ci asd_ha->seq.next_scb.vaddr = NULL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci dma_pool_destroy(asd_ha->scb_pool); 60662306a36Sopenharmony_ci asd_ha->scb_pool = NULL; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistruct kmem_cache *asd_dma_token_cache; 61062306a36Sopenharmony_cistruct kmem_cache *asd_ascb_cache; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int asd_create_global_caches(void) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci if (!asd_dma_token_cache) { 61562306a36Sopenharmony_ci asd_dma_token_cache 61662306a36Sopenharmony_ci = kmem_cache_create(ASD_DRIVER_NAME "_dma_token", 61762306a36Sopenharmony_ci sizeof(struct asd_dma_tok), 61862306a36Sopenharmony_ci 0, 61962306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, 62062306a36Sopenharmony_ci NULL); 62162306a36Sopenharmony_ci if (!asd_dma_token_cache) { 62262306a36Sopenharmony_ci asd_printk("couldn't create dma token cache\n"); 62362306a36Sopenharmony_ci return -ENOMEM; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!asd_ascb_cache) { 62862306a36Sopenharmony_ci asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb", 62962306a36Sopenharmony_ci sizeof(struct asd_ascb), 63062306a36Sopenharmony_ci 0, 63162306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, 63262306a36Sopenharmony_ci NULL); 63362306a36Sopenharmony_ci if (!asd_ascb_cache) { 63462306a36Sopenharmony_ci asd_printk("couldn't create ascb cache\n"); 63562306a36Sopenharmony_ci goto Err; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ciErr: 64162306a36Sopenharmony_ci kmem_cache_destroy(asd_dma_token_cache); 64262306a36Sopenharmony_ci asd_dma_token_cache = NULL; 64362306a36Sopenharmony_ci return -ENOMEM; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic void asd_destroy_global_caches(void) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci kmem_cache_destroy(asd_dma_token_cache); 64962306a36Sopenharmony_ci asd_dma_token_cache = NULL; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci kmem_cache_destroy(asd_ascb_cache); 65262306a36Sopenharmony_ci asd_ascb_cache = NULL; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int asd_register_sas_ha(struct asd_ha_struct *asd_ha) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci int i; 65862306a36Sopenharmony_ci struct asd_sas_phy **sas_phys = 65962306a36Sopenharmony_ci kcalloc(ASD_MAX_PHYS, sizeof(*sas_phys), GFP_KERNEL); 66062306a36Sopenharmony_ci struct asd_sas_port **sas_ports = 66162306a36Sopenharmony_ci kcalloc(ASD_MAX_PHYS, sizeof(*sas_ports), GFP_KERNEL); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!sas_phys || !sas_ports) { 66462306a36Sopenharmony_ci kfree(sas_phys); 66562306a36Sopenharmony_ci kfree(sas_ports); 66662306a36Sopenharmony_ci return -ENOMEM; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name; 67062306a36Sopenharmony_ci asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0]; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci for (i = 0; i < ASD_MAX_PHYS; i++) { 67362306a36Sopenharmony_ci sas_phys[i] = &asd_ha->phys[i].sas_phy; 67462306a36Sopenharmony_ci sas_ports[i] = &asd_ha->ports[i]; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci asd_ha->sas_ha.sas_phy = sas_phys; 67862306a36Sopenharmony_ci asd_ha->sas_ha.sas_port= sas_ports; 67962306a36Sopenharmony_ci asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci return sas_register_ha(&asd_ha->sas_ha); 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci int err; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci err = sas_unregister_ha(&asd_ha->sas_ha); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci sas_remove_host(asd_ha->sas_ha.shost); 69162306a36Sopenharmony_ci scsi_host_put(asd_ha->sas_ha.shost); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci kfree(asd_ha->sas_ha.sas_phy); 69462306a36Sopenharmony_ci kfree(asd_ha->sas_ha.sas_port); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return err; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci const struct asd_pcidev_struct *asd_dev; 70262306a36Sopenharmony_ci unsigned asd_id = (unsigned) id->driver_data; 70362306a36Sopenharmony_ci struct asd_ha_struct *asd_ha; 70462306a36Sopenharmony_ci struct Scsi_Host *shost; 70562306a36Sopenharmony_ci int err; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) { 70862306a36Sopenharmony_ci asd_printk("wrong driver_data in PCI table\n"); 70962306a36Sopenharmony_ci return -ENODEV; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if ((err = pci_enable_device(dev))) { 71362306a36Sopenharmony_ci asd_printk("couldn't enable device %s\n", pci_name(dev)); 71462306a36Sopenharmony_ci return err; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci pci_set_master(dev); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci err = -ENOMEM; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *)); 72262306a36Sopenharmony_ci if (!shost) 72362306a36Sopenharmony_ci goto Err; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci asd_dev = &asd_pcidev_data[asd_id]; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); 72862306a36Sopenharmony_ci if (!asd_ha) { 72962306a36Sopenharmony_ci asd_printk("out of memory\n"); 73062306a36Sopenharmony_ci goto Err_put; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci asd_ha->pcidev = dev; 73362306a36Sopenharmony_ci asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; 73462306a36Sopenharmony_ci asd_ha->sas_ha.lldd_ha = asd_ha; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci asd_ha->bios_status = FLASH_OK; 73762306a36Sopenharmony_ci asd_ha->name = asd_dev->name; 73862306a36Sopenharmony_ci asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha; 74162306a36Sopenharmony_ci asd_ha->sas_ha.shost = shost; 74262306a36Sopenharmony_ci shost->transportt = aic94xx_transport_template; 74362306a36Sopenharmony_ci shost->max_id = ~0; 74462306a36Sopenharmony_ci shost->max_lun = ~0; 74562306a36Sopenharmony_ci shost->max_cmd_len = 16; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci err = scsi_add_host(shost, &dev->dev); 74862306a36Sopenharmony_ci if (err) 74962306a36Sopenharmony_ci goto Err_free; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci err = asd_dev->setup(asd_ha); 75262306a36Sopenharmony_ci if (err) 75362306a36Sopenharmony_ci goto Err_remove; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(64)); 75662306a36Sopenharmony_ci if (err) 75762306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); 75862306a36Sopenharmony_ci if (err) { 75962306a36Sopenharmony_ci err = -ENODEV; 76062306a36Sopenharmony_ci asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); 76162306a36Sopenharmony_ci goto Err_remove; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci pci_set_drvdata(dev, asd_ha); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci err = asd_map_ha(asd_ha); 76762306a36Sopenharmony_ci if (err) 76862306a36Sopenharmony_ci goto Err_remove; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci err = asd_create_ha_caches(asd_ha); 77162306a36Sopenharmony_ci if (err) 77262306a36Sopenharmony_ci goto Err_unmap; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci err = asd_init_hw(asd_ha); 77562306a36Sopenharmony_ci if (err) 77662306a36Sopenharmony_ci goto Err_free_cache; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled " 77962306a36Sopenharmony_ci "phys, flash %s, BIOS %s%d\n", 78062306a36Sopenharmony_ci pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr), 78162306a36Sopenharmony_ci asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys, 78262306a36Sopenharmony_ci asd_ha->hw_prof.num_phys, 78362306a36Sopenharmony_ci asd_ha->hw_prof.flash.present ? "present" : "not present", 78462306a36Sopenharmony_ci asd_ha->hw_prof.bios.present ? "build " : "not present", 78562306a36Sopenharmony_ci asd_ha->hw_prof.bios.bld); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci shost->can_queue = asd_ha->seq.can_queue; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (use_msi) 79062306a36Sopenharmony_ci pci_enable_msi(asd_ha->pcidev); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED, 79362306a36Sopenharmony_ci ASD_DRIVER_NAME, asd_ha); 79462306a36Sopenharmony_ci if (err) { 79562306a36Sopenharmony_ci asd_printk("couldn't get irq %d for %s\n", 79662306a36Sopenharmony_ci asd_ha->pcidev->irq, pci_name(asd_ha->pcidev)); 79762306a36Sopenharmony_ci goto Err_irq; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci asd_enable_ints(asd_ha); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci err = asd_init_post_escbs(asd_ha); 80262306a36Sopenharmony_ci if (err) { 80362306a36Sopenharmony_ci asd_printk("couldn't post escbs for %s\n", 80462306a36Sopenharmony_ci pci_name(asd_ha->pcidev)); 80562306a36Sopenharmony_ci goto Err_escbs; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci ASD_DPRINTK("escbs posted\n"); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci err = asd_create_dev_attrs(asd_ha); 81062306a36Sopenharmony_ci if (err) 81162306a36Sopenharmony_ci goto Err_dev_attrs; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci err = asd_register_sas_ha(asd_ha); 81462306a36Sopenharmony_ci if (err) 81562306a36Sopenharmony_ci goto Err_reg_sas; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci scsi_scan_host(shost); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ciErr_reg_sas: 82262306a36Sopenharmony_ci asd_remove_dev_attrs(asd_ha); 82362306a36Sopenharmony_ciErr_dev_attrs: 82462306a36Sopenharmony_ciErr_escbs: 82562306a36Sopenharmony_ci asd_disable_ints(asd_ha); 82662306a36Sopenharmony_ci free_irq(dev->irq, asd_ha); 82762306a36Sopenharmony_ciErr_irq: 82862306a36Sopenharmony_ci if (use_msi) 82962306a36Sopenharmony_ci pci_disable_msi(dev); 83062306a36Sopenharmony_ci asd_chip_hardrst(asd_ha); 83162306a36Sopenharmony_ciErr_free_cache: 83262306a36Sopenharmony_ci asd_destroy_ha_caches(asd_ha); 83362306a36Sopenharmony_ciErr_unmap: 83462306a36Sopenharmony_ci asd_unmap_ha(asd_ha); 83562306a36Sopenharmony_ciErr_remove: 83662306a36Sopenharmony_ci scsi_remove_host(shost); 83762306a36Sopenharmony_ciErr_free: 83862306a36Sopenharmony_ci kfree(asd_ha); 83962306a36Sopenharmony_ciErr_put: 84062306a36Sopenharmony_ci scsi_host_put(shost); 84162306a36Sopenharmony_ciErr: 84262306a36Sopenharmony_ci pci_disable_device(dev); 84362306a36Sopenharmony_ci return err; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic void asd_free_queues(struct asd_ha_struct *asd_ha) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci unsigned long flags; 84962306a36Sopenharmony_ci LIST_HEAD(pending); 85062306a36Sopenharmony_ci struct list_head *n, *pos; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); 85362306a36Sopenharmony_ci asd_ha->seq.pending = 0; 85462306a36Sopenharmony_ci list_splice_init(&asd_ha->seq.pend_q, &pending); 85562306a36Sopenharmony_ci spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (!list_empty(&pending)) 85862306a36Sopenharmony_ci ASD_DPRINTK("Uh-oh! Pending is not empty!\n"); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci list_for_each_safe(pos, n, &pending) { 86162306a36Sopenharmony_ci struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list); 86262306a36Sopenharmony_ci /* 86362306a36Sopenharmony_ci * Delete unexpired ascb timers. This may happen if we issue 86462306a36Sopenharmony_ci * a CONTROL PHY scb to an adapter and rmmod before the scb 86562306a36Sopenharmony_ci * times out. Apparently we don't wait for the CONTROL PHY 86662306a36Sopenharmony_ci * to complete, so it doesn't matter if we kill the timer. 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci del_timer_sync(&ascb->timer); 86962306a36Sopenharmony_ci WARN_ON(ascb->scb->header.opcode != CONTROL_PHY); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci list_del_init(pos); 87262306a36Sopenharmony_ci ASD_DPRINTK("freeing from pending\n"); 87362306a36Sopenharmony_ci asd_ascb_free(ascb); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic void asd_turn_off_leds(struct asd_ha_struct *asd_ha) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci u8 phy_mask = asd_ha->hw_prof.enabled_phys; 88062306a36Sopenharmony_ci u8 i; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci for_each_phy(phy_mask, phy_mask, i) { 88362306a36Sopenharmony_ci asd_turn_led(asd_ha, i, 0); 88462306a36Sopenharmony_ci asd_control_led(asd_ha, i, 0); 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void asd_pci_remove(struct pci_dev *dev) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct asd_ha_struct *asd_ha = pci_get_drvdata(dev); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!asd_ha) 89362306a36Sopenharmony_ci return; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci asd_unregister_sas_ha(asd_ha); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci asd_disable_ints(asd_ha); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci asd_remove_dev_attrs(asd_ha); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* XXX more here as needed */ 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci free_irq(dev->irq, asd_ha); 90462306a36Sopenharmony_ci if (use_msi) 90562306a36Sopenharmony_ci pci_disable_msi(asd_ha->pcidev); 90662306a36Sopenharmony_ci asd_turn_off_leds(asd_ha); 90762306a36Sopenharmony_ci asd_chip_hardrst(asd_ha); 90862306a36Sopenharmony_ci asd_free_queues(asd_ha); 90962306a36Sopenharmony_ci asd_destroy_ha_caches(asd_ha); 91062306a36Sopenharmony_ci asd_unmap_ha(asd_ha); 91162306a36Sopenharmony_ci kfree(asd_ha); 91262306a36Sopenharmony_ci pci_disable_device(dev); 91362306a36Sopenharmony_ci return; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic void asd_scan_start(struct Scsi_Host *shost) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci struct asd_ha_struct *asd_ha; 91962306a36Sopenharmony_ci int err; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha; 92262306a36Sopenharmony_ci err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); 92362306a36Sopenharmony_ci if (err) 92462306a36Sopenharmony_ci asd_printk("Couldn't enable phys, err:%d\n", err); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic int asd_scan_finished(struct Scsi_Host *shost, unsigned long time) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci /* give the phy enabling interrupt event time to come in (1s 93062306a36Sopenharmony_ci * is empirically about all it takes) */ 93162306a36Sopenharmony_ci if (time < HZ) 93262306a36Sopenharmony_ci return 0; 93362306a36Sopenharmony_ci /* Wait for discovery to finish */ 93462306a36Sopenharmony_ci sas_drain_work(SHOST_TO_SAS_HA(shost)); 93562306a36Sopenharmony_ci return 1; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic ssize_t version_show(struct device_driver *driver, char *buf) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_cistatic DRIVER_ATTR_RO(version); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic int asd_create_driver_attrs(struct device_driver *driver) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci return driver_create_file(driver, &driver_attr_version); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void asd_remove_driver_attrs(struct device_driver *driver) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci driver_remove_file(driver, &driver_attr_version); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic struct sas_domain_function_template aic94xx_transport_functions = { 95562306a36Sopenharmony_ci .lldd_dev_found = asd_dev_found, 95662306a36Sopenharmony_ci .lldd_dev_gone = asd_dev_gone, 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci .lldd_execute_task = asd_execute_task, 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci .lldd_abort_task = asd_abort_task, 96162306a36Sopenharmony_ci .lldd_abort_task_set = asd_abort_task_set, 96262306a36Sopenharmony_ci .lldd_clear_task_set = asd_clear_task_set, 96362306a36Sopenharmony_ci .lldd_I_T_nexus_reset = asd_I_T_nexus_reset, 96462306a36Sopenharmony_ci .lldd_lu_reset = asd_lu_reset, 96562306a36Sopenharmony_ci .lldd_query_task = asd_query_task, 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci .lldd_clear_nexus_port = asd_clear_nexus_port, 96862306a36Sopenharmony_ci .lldd_clear_nexus_ha = asd_clear_nexus_ha, 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci .lldd_control_phy = asd_control_phy, 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci .lldd_ata_set_dmamode = asd_set_dmamode, 97362306a36Sopenharmony_ci}; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic const struct pci_device_id aic94xx_pci_table[] = { 97662306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1}, 97762306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1}, 97862306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1}, 97962306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1}, 98062306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1}, 98162306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2}, 98262306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2}, 98362306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2}, 98462306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2}, 98562306a36Sopenharmony_ci {} 98662306a36Sopenharmony_ci}; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, aic94xx_pci_table); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic struct pci_driver aic94xx_pci_driver = { 99162306a36Sopenharmony_ci .name = ASD_DRIVER_NAME, 99262306a36Sopenharmony_ci .id_table = aic94xx_pci_table, 99362306a36Sopenharmony_ci .probe = asd_pci_probe, 99462306a36Sopenharmony_ci .remove = asd_pci_remove, 99562306a36Sopenharmony_ci}; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int __init aic94xx_init(void) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci int err; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION, 100362306a36Sopenharmony_ci ASD_DRIVER_VERSION); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci err = asd_create_global_caches(); 100662306a36Sopenharmony_ci if (err) 100762306a36Sopenharmony_ci return err; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci aic94xx_transport_template = 101062306a36Sopenharmony_ci sas_domain_attach_transport(&aic94xx_transport_functions); 101162306a36Sopenharmony_ci if (!aic94xx_transport_template) { 101262306a36Sopenharmony_ci err = -ENOMEM; 101362306a36Sopenharmony_ci goto out_destroy_caches; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci err = pci_register_driver(&aic94xx_pci_driver); 101762306a36Sopenharmony_ci if (err) 101862306a36Sopenharmony_ci goto out_release_transport; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci err = asd_create_driver_attrs(&aic94xx_pci_driver.driver); 102162306a36Sopenharmony_ci if (err) 102262306a36Sopenharmony_ci goto out_unregister_pcidrv; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return err; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci out_unregister_pcidrv: 102762306a36Sopenharmony_ci pci_unregister_driver(&aic94xx_pci_driver); 102862306a36Sopenharmony_ci out_release_transport: 102962306a36Sopenharmony_ci sas_release_transport(aic94xx_transport_template); 103062306a36Sopenharmony_ci out_destroy_caches: 103162306a36Sopenharmony_ci asd_destroy_global_caches(); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci return err; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic void __exit aic94xx_exit(void) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci asd_remove_driver_attrs(&aic94xx_pci_driver.driver); 103962306a36Sopenharmony_ci pci_unregister_driver(&aic94xx_pci_driver); 104062306a36Sopenharmony_ci sas_release_transport(aic94xx_transport_template); 104162306a36Sopenharmony_ci asd_release_firmware(); 104262306a36Sopenharmony_ci asd_destroy_global_caches(); 104362306a36Sopenharmony_ci asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, 104462306a36Sopenharmony_ci ASD_DRIVER_VERSION); 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cimodule_init(aic94xx_init); 104862306a36Sopenharmony_cimodule_exit(aic94xx_exit); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciMODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); 105162306a36Sopenharmony_ciMODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION); 105262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 105362306a36Sopenharmony_ciMODULE_VERSION(ASD_DRIVER_VERSION); 1054