[SCSI] fcoe, libfc: fix double fcoe_softc memory alloc
[safe/jmp/linux-2.6] / drivers / scsi / aic94xx / aic94xx_init.c
index fbc82b0..2a730c4 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 
 #include <scsi/scsi_host.h>
 
 #include "aic94xx_reg.h"
 #include "aic94xx_hwi.h"
 #include "aic94xx_seq.h"
+#include "aic94xx_sds.h"
 
 /* The format is "version.release.patchlevel" */
-#define ASD_DRIVER_VERSION "1.0.2"
+#define ASD_DRIVER_VERSION "1.0.3"
 
 static int use_msi = 0;
 module_param_named(use_msi, use_msi, int, S_IRUGO);
@@ -54,9 +56,9 @@ MODULE_PARM_DESC(collector, "\n"
        "\tThe aic94xx SAS LLDD supports both modes.\n"
        "\tDefault: 0 (Direct Mode).\n");
 
-char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
-
 static struct scsi_transport_template *aic94xx_transport_template;
+static int asd_scan_finished(struct Scsi_Host *, unsigned long);
+static void asd_scan_start(struct Scsi_Host *);
 
 static struct scsi_host_template aic94xx_sht = {
        .module                 = THIS_MODULE,
@@ -66,6 +68,8 @@ static struct scsi_host_template aic94xx_sht = {
        .target_alloc           = sas_target_alloc,
        .slave_configure        = sas_slave_configure,
        .slave_destroy          = sas_slave_destroy,
+       .scan_finished          = asd_scan_finished,
+       .scan_start             = asd_scan_start,
        .change_queue_depth     = sas_change_queue_depth,
        .change_queue_type      = sas_change_queue_type,
        .bios_param             = sas_bios_param,
@@ -75,6 +79,11 @@ static struct scsi_host_template aic94xx_sht = {
        .sg_tablesize           = SG_ALL,
        .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
        .use_clustering         = ENABLE_CLUSTERING,
+       .eh_device_reset_handler        = sas_eh_device_reset_handler,
+       .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
+       .slave_alloc            = sas_slave_alloc,
+       .target_destroy         = sas_target_destroy,
+       .ioctl                  = sas_ioctl,
 };
 
 static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -125,7 +134,7 @@ Err:
        return err;
 }
 
-static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
 {
        struct asd_ha_addrspace *io_handle;
 
@@ -162,7 +171,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
        return err;
 }
 
-static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
 {
        pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
 }
@@ -199,7 +208,7 @@ Err:
        return err;
 }
 
-static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
 {
        if (asd_ha->iospace)
                asd_unmap_ioport(asd_ha);
@@ -217,13 +226,8 @@ static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
 {
        int err, i;
 
-       err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
-                                  &asd_ha->revision_id);
-       if (err) {
-               asd_printk("couldn't read REVISION ID register of %s\n",
-                          pci_name(asd_ha->pcidev));
-               goto Err;
-       }
+       asd_ha->revision_id = asd_ha->pcidev->revision;
+
        err = -ENODEV;
        if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
                asd_printk("%s is revision %s (%X), which is not supported\n",
@@ -234,7 +238,7 @@ static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
        }
        /* Provide some sane default values. */
        asd_ha->hw_prof.max_scbs = 512;
-       asd_ha->hw_prof.max_ddbs = 128;
+       asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS;
        asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
        /* All phys are enabled, by default. */
        asd_ha->hw_prof.enabled_phys = 0xFF;
@@ -309,6 +313,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
 }
 static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
 
+#define FLASH_CMD_NONE      0x00
+#define FLASH_CMD_UPDATE    0x01
+#define FLASH_CMD_VERIFY    0x02
+
+struct flash_command {
+     u8      command[8];
+     int     code;
+};
+
+static struct flash_command flash_command_table[] =
+{
+     {"verify",      FLASH_CMD_VERIFY},
+     {"update",      FLASH_CMD_UPDATE},
+     {"",            FLASH_CMD_NONE}      /* Last entry should be NULL. */
+};
+
+struct error_bios {
+     char    *reason;
+     int     err_code;
+};
+
+static struct error_bios flash_error_table[] =
+{
+     {"Failed to open bios image file",      FAIL_OPEN_BIOS_FILE},
+     {"PCI ID mismatch",                     FAIL_CHECK_PCI_ID},
+     {"Checksum mismatch",                   FAIL_CHECK_SUM},
+     {"Unknown Error",                       FAIL_UNKNOWN},
+     {"Failed to verify.",                   FAIL_VERIFY},
+     {"Failed to reset flash chip.",         FAIL_RESET_FLASH},
+     {"Failed to find flash chip type.",     FAIL_FIND_FLASH_ID},
+     {"Failed to erash flash chip.",         FAIL_ERASE_FLASH},
+     {"Failed to program flash chip.",       FAIL_WRITE_FLASH},
+     {"Flash in progress",                   FLASH_IN_PROGRESS},
+     {"Image file size Error",               FAIL_FILE_SIZE},
+     {"Input parameter error",               FAIL_PARAMETERS},
+     {"Out of memory",                       FAIL_OUT_MEMORY},
+     {"OK", 0} /* Last entry err_code = 0. */
+};
+
+static ssize_t asd_store_update_bios(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+       char *cmd_ptr, *filename_ptr;
+       struct bios_file_header header, *hdr_ptr;
+       int res, i;
+       u32 csum = 0;
+       int flash_command = FLASH_CMD_NONE;
+       int err = 0;
+
+       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+
+       if (!cmd_ptr) {
+               err = FAIL_OUT_MEMORY;
+               goto out;
+       }
+
+       filename_ptr = cmd_ptr + count;
+       res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
+       if (res != 2) {
+               err = FAIL_PARAMETERS;
+               goto out1;
+       }
+
+       for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
+               if (!memcmp(flash_command_table[i].command,
+                                cmd_ptr, strlen(cmd_ptr))) {
+                       flash_command = flash_command_table[i].code;
+                       break;
+               }
+       }
+       if (flash_command == FLASH_CMD_NONE) {
+               err = FAIL_PARAMETERS;
+               goto out1;
+       }
+
+       if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
+               err = FLASH_IN_PROGRESS;
+               goto out1;
+       }
+       err = request_firmware(&asd_ha->bios_image,
+                                  filename_ptr,
+                                  &asd_ha->pcidev->dev);
+       if (err) {
+               asd_printk("Failed to load bios image file %s, error %d\n",
+                          filename_ptr, err);
+               err = FAIL_OPEN_BIOS_FILE;
+               goto out1;
+       }
+
+       hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
+
+       if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
+               hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
+               (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
+               hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
+
+               ASD_DPRINTK("The PCI vendor or device id does not match\n");
+               ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
+               " pci vendor=%x pci dev=%x\n",
+               hdr_ptr->contrl_id.vendor,
+               hdr_ptr->contrl_id.device,
+               hdr_ptr->contrl_id.sub_vendor,
+               hdr_ptr->contrl_id.sub_device,
+               asd_ha->pcidev->vendor,
+               asd_ha->pcidev->device);
+               err = FAIL_CHECK_PCI_ID;
+               goto out2;
+       }
+
+       if (hdr_ptr->filelen != asd_ha->bios_image->size) {
+               err = FAIL_FILE_SIZE;
+               goto out2;
+       }
+
+       /* calculate checksum */
+       for (i = 0; i < hdr_ptr->filelen; i++)
+               csum += asd_ha->bios_image->data[i];
+
+       if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
+               ASD_DPRINTK("BIOS file checksum mismatch\n");
+               err = FAIL_CHECK_SUM;
+               goto out2;
+       }
+       if (flash_command == FLASH_CMD_UPDATE) {
+               asd_ha->bios_status = FLASH_IN_PROGRESS;
+               err = asd_write_flash_seg(asd_ha,
+                       &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+                       0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+               if (!err)
+                       err = asd_verify_flash_seg(asd_ha,
+                               &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+                               0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+       } else {
+               asd_ha->bios_status = FLASH_IN_PROGRESS;
+               err = asd_verify_flash_seg(asd_ha,
+                       &asd_ha->bios_image->data[sizeof(header)],
+                       0, hdr_ptr->filelen-sizeof(header));
+       }
+
+out2:
+       release_firmware(asd_ha->bios_image);
+out1:
+       kfree(cmd_ptr);
+out:
+       asd_ha->bios_status = err;
+
+       if (!err)
+               return count;
+       else
+               return -err;
+}
+
+static ssize_t asd_show_update_bios(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       int i;
+       struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+
+       for (i = 0; flash_error_table[i].err_code != 0; i++) {
+               if (flash_error_table[i].err_code == asd_ha->bios_status)
+                       break;
+       }
+       if (asd_ha->bios_status != FLASH_IN_PROGRESS)
+               asd_ha->bios_status = FLASH_OK;
+
+       return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
+                       flash_error_table[i].err_code,
+                       flash_error_table[i].reason);
+}
+
+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
+       asd_show_update_bios, asd_store_update_bios);
+
 static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
 {
        int err;
@@ -324,9 +503,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
        err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
        if (err)
                goto err_biosb;
+       err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
+       if (err)
+               goto err_update_bios;
 
        return 0;
 
+err_update_bios:
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
 err_biosb:
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
 err_rev:
@@ -339,15 +523,16 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
        device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+       device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
 }
 
 /* The first entry, 0, is used for dynamic ids, the rest for devices
  * we know about.
  */
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
        const char * name;
        int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] = {
+} asd_pcidev_data[] __devinitconst = {
        /* Id 0 is used for dynamic ids. */
        { .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",
          .setup = asd_aic9410_setup
@@ -360,7 +545,7 @@ static struct asd_pcidev_struct {
        },
 };
 
-static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+static int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
 {
        asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
                                           &asd_ha->pcidev->dev,
@@ -378,7 +563,7 @@ static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
  * asd_free_edbs -- free empty data buffers
  * asd_ha: pointer to host adapter structure
  */
-static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
+static void asd_free_edbs(struct asd_ha_struct *asd_ha)
 {
        struct asd_seq_data *seq = &asd_ha->seq;
        int i;
@@ -389,7 +574,7 @@ static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
        seq->edb_arr = NULL;
 }
 
-static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+static void asd_free_escbs(struct asd_ha_struct *asd_ha)
 {
        struct asd_seq_data *seq = &asd_ha->seq;
        int i;
@@ -404,7 +589,7 @@ static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
        seq->escb_arr = NULL;
 }
 
-static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+static void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
 {
        int i;
 
@@ -461,7 +646,7 @@ static int asd_create_global_caches(void)
                                            sizeof(struct asd_dma_tok),
                                            0,
                                            SLAB_HWCACHE_ALIGN,
-                                           NULL, NULL);
+                                           NULL);
                if (!asd_dma_token_cache) {
                        asd_printk("couldn't create dma token cache\n");
                        return -ENOMEM;
@@ -473,7 +658,7 @@ static int asd_create_global_caches(void)
                                                   sizeof(struct asd_ascb),
                                                   0,
                                                   SLAB_HWCACHE_ALIGN,
-                                                  NULL, NULL);
+                                                  NULL);
                if (!asd_ascb_cache) {
                        asd_printk("couldn't create ascb cache\n");
                        goto Err;
@@ -526,6 +711,7 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
        asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
 
        asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+       asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num;
 
        return sas_register_ha(&asd_ha->sas_ha);
 }
@@ -549,7 +735,7 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
 static int __devinit asd_pci_probe(struct pci_dev *dev,
                                   const struct pci_device_id *id)
 {
-       struct asd_pcidev_struct *asd_dev;
+       const struct asd_pcidev_struct *asd_dev;
        unsigned asd_id = (unsigned) id->driver_data;
        struct asd_ha_struct *asd_ha;
        struct Scsi_Host *shost;
@@ -578,12 +764,13 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
        if (!asd_ha) {
                asd_printk("out of memory\n");
-               goto Err;
+               goto Err_put;
        }
        asd_ha->pcidev = dev;
-       asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+       asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
        asd_ha->sas_ha.lldd_ha = asd_ha;
 
+       asd_ha->bios_status = FLASH_OK;
        asd_ha->name = asd_dev->name;
        asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
 
@@ -595,16 +782,12 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        shost->max_cmd_len = 16;
 
        err = scsi_add_host(shost, &dev->dev);
-       if (err) {
-               scsi_host_put(shost);
+       if (err)
                goto Err_free;
-       }
-
-
 
        err = asd_dev->setup(asd_ha);
        if (err)
-               goto Err_free;
+               goto Err_remove;
 
        err = -ENODEV;
        if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
@@ -615,14 +798,14 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
                ;
        else {
                asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
-               goto Err_free;
+               goto Err_remove;
        }
 
        pci_set_drvdata(dev, asd_ha);
 
        err = asd_map_ha(asd_ha);
        if (err)
-               goto Err_free;
+               goto Err_remove;
 
        err = asd_create_ha_caches(asd_ha);
         if (err)
@@ -646,7 +829,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        if (use_msi)
                pci_enable_msi(asd_ha->pcidev);
 
-       err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+       err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED,
                          ASD_DRIVER_NAME, asd_ha);
        if (err) {
                asd_printk("couldn't get irq %d for %s\n",
@@ -671,21 +854,10 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
        if (err)
                goto Err_reg_sas;
 
-       err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
-       if (err) {
-               asd_printk("coudln't enable phys, err:%d\n", err);
-               goto Err_en_phys;
-       }
-       ASD_DPRINTK("enabled phys\n");
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       ssleep(1);
-       /* Wait for discovery to finish */
-       scsi_flush_work(asd_ha->sas_ha.core.shost);
+       scsi_scan_host(shost);
 
        return 0;
-Err_en_phys:
-       asd_unregister_sas_ha(asd_ha);
+
 Err_reg_sas:
        asd_remove_dev_attrs(asd_ha);
 Err_dev_attrs:
@@ -700,9 +872,12 @@ Err_free_cache:
        asd_destroy_ha_caches(asd_ha);
 Err_unmap:
        asd_unmap_ha(asd_ha);
+Err_remove:
+       scsi_remove_host(shost);
 Err_free:
        kfree(asd_ha);
-       scsi_remove_host(shost);
+Err_put:
+       scsi_host_put(shost);
 Err:
        pci_disable_device(dev);
        return err;
@@ -778,6 +953,28 @@ static void __devexit asd_pci_remove(struct pci_dev *dev)
        return;
 }
 
+static void asd_scan_start(struct Scsi_Host *shost)
+{
+       struct asd_ha_struct *asd_ha;
+       int err;
+
+       asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha;
+       err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+       if (err)
+               asd_printk("Couldn't enable phys, err:%d\n", err);
+}
+
+static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       /* give the phy enabling interrupt event time to come in (1s
+        * is empirically about all it takes) */
+       if (time < HZ)
+               return 0;
+       /* Wait for discovery to finish */
+       scsi_flush_work(shost);
+       return 1;
+}
+
 static ssize_t asd_version_show(struct device_driver *driver, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
@@ -804,7 +1001,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
        .lldd_abort_task_set    = asd_abort_task_set,
        .lldd_clear_aca         = asd_clear_aca,
        .lldd_clear_task_set    = asd_clear_task_set,
-       .lldd_I_T_nexus_reset   = NULL,
+       .lldd_I_T_nexus_reset   = asd_I_T_nexus_reset,
        .lldd_lu_reset          = asd_lu_reset,
        .lldd_query_task        = asd_query_task,
 
@@ -815,22 +1012,15 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
 };
 
 static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
-        0, 0, 1},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
-        0, 0, 2},
-       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
-        0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2},
+       {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2},
        {}
 };
 
@@ -885,6 +1075,7 @@ static void __exit aic94xx_exit(void)
        asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
        pci_unregister_driver(&aic94xx_pci_driver);
        sas_release_transport(aic94xx_transport_template);
+       asd_release_firmware();
        asd_destroy_global_caches();
        asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
                   ASD_DRIVER_VERSION);