1. Create a file "update_bios" in sysfs to allow user to update bios
    from user space.

 2. The aic94xx BIOS image file can be downloaded from web site 
    
"http://www.adaptec.com/en-US/downloads/bios_fw/bios_fw_ver?productId=SAS-48300&dn=Adaptec+Serial+Attached+SCSI+48300";
    and copy the BIOS image into /lib/firmware folder.

 3. The aic994xx will accept "update bios_file" and "verify bios_file"
    commands to perform update and verify BIOS image .

      For example:

       Type "echo "update asc483c01.ufi" > /sys/devices/.../update_bios"
            to update BIOS image from /lib/firmware/as483c01.ufi file into
            HBA's flash memory.

       Type "echo "verify asc483c01.ufi" > /sys/devices/.../update_bios"
            to verify BIOS image between /lib/firmware/asc48c01.ufi file and
            HBA's flash memory.

 4. Type "cat  /sys/devices/.../update_bios" to view the status or result
    of updating BIOS.




Signed-off-by: Gilbert Wu <[EMAIL PROTECTED]>


diff -urN a/drivers/scsi/aic94xx/aic94xx_hwi.h 
b/drivers/scsi/aic94xx/aic94xx_hwi.h
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h        2007-10-10 17:13:55.000000000 
-0700
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h        2007-10-10 17:16:04.000000000 
-0700
@@ -72,6 +72,7 @@
        u8     manuf;
        u8     dev_id;
        u8     sec_prot;
+        u8     method;
 
        u32    dir_offs;
 };
@@ -216,6 +217,8 @@
        struct dma_pool  *scb_pool;
 
        struct asd_seq_data  seq; /* sequencer related */
+        u32    bios_status;
+       const struct firmware *bios_image;
 };
 
 /* ---------- Common macros ---------- */
diff -urN a/drivers/scsi/aic94xx/aic94xx_init.c 
b/drivers/scsi/aic94xx/aic94xx_init.c
--- a/drivers/scsi/aic94xx/aic94xx_init.c       2007-10-10 17:13:29.000000000 
-0700
+++ b/drivers/scsi/aic94xx/aic94xx_init.c       2007-10-10 17:15:58.000000000 
-0700
@@ -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>
 
@@ -36,6 +37,7 @@
 #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.3"
@@ -313,6 +315,179 @@
 }
 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 = kmalloc(count*2, GFP_KERNEL);
+
+       if (!cmd_ptr) {
+               err=FAIL_OUT_MEMORY;
+               goto out;
+       }
+
+       memset(cmd_ptr,0,count*2);
+       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 id 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:
+       // free buffer
+       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;
@@ -328,8 +503,13 @@
        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);
@@ -343,6 +523,7 @@
        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
@@ -589,6 +770,7 @@
        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));
 
diff -urN a/drivers/scsi/aic94xx/aic94xx_sds.c 
b/drivers/scsi/aic94xx/aic94xx_sds.c
--- a/drivers/scsi/aic94xx/aic94xx_sds.c        2007-10-10 17:13:43.000000000 
-0700
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c        2007-10-10 17:16:10.000000000 
-0700
@@ -30,7 +30,7 @@
 
 #include "aic94xx.h"
 #include "aic94xx_reg.h"
-
+#include "aic94xx_sds.h"
 /* ---------- OCM stuff ---------- */
 
 struct asd_ocm_dir_ent {
@@ -1083,3 +1083,443 @@
        kfree(flash_dir);
        return err;
 }
+/*
+ * Function:
+ *     asd_hwi_write_nv_segment()
+ *
+ * Description:
+ *     Writes data to an NVRAM segment.
+ */
+int
+asd_verify_flash_seg(struct asd_ha_struct *asd_ha, 
+               void *src,u32 dest_offset, u32 bytes_to_verify)
+{
+       u8 *src_buf;
+       u8 flash_char;
+       int err;
+       u32 nv_offset, reg, i;
+
+
+       reg = asd_ha->hw_prof.flash.bar;
+       src_buf = NULL;
+
+       err = FLASH_OK;
+       nv_offset = dest_offset;
+       src_buf = (u8 *)src;
+       for (i = 0; i < bytes_to_verify; i++) {
+
+               flash_char = asd_read_reg_byte(asd_ha,reg +nv_offset+i);
+               if (flash_char != src_buf[i])           {
+                       err = FAIL_VERIFY;
+                       break;
+               }
+       }
+       return (err);
+}
+/*
+ * Function:
+ *     asd_hwi_write_nv_segment()
+ *
+ * Description:
+ *     Writes data to an NVRAM segment.
+ */
+int
+asd_write_flash_seg(struct asd_ha_struct *asd_ha, 
+               void *src,u32 dest_offset, u32 bytes_to_write)
+{
+    u8 *src_buf;
+       u32 nv_offset, reg, i;
+       int err;
+
+
+       reg = asd_ha->hw_prof.flash.bar;
+               src_buf = NULL;
+
+       err = asd_check_flash_type(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't find the type of flah(%d)\n", err);
+               return err;
+       }
+
+       nv_offset = dest_offset;
+       err = asd_erase_nv_sector(asd_ha, nv_offset,bytes_to_write);
+       if (err) {
+               ASD_DPRINTK("Erase failed at offset:0x%x\n",
+                       nv_offset);
+               return err;
+       }
+
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+               return err;
+       }
+
+       src_buf = (u8 *)src;
+       for (i = 0; i < bytes_to_write; i++) {
+               /* Setup program command sequence */
+               switch (asd_ha->hw_prof.flash.method) {
+               case FLASH_METHOD_A:
+               {
+
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0xAAA), 0xA0);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + nv_offset + i),
+                                       (*(src_buf + i)));
+                       break;
+               }
+               case FLASH_METHOD_B:
+               {
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + 0x555), 0xA0);
+                       asd_write_reg_byte(asd_ha, 
+                                       (reg + nv_offset + i),
+                                       (*(src_buf + i)));
+                       break;
+               }
+               default:
+                       break;
+               }
+               if (asd_chk_write_status(asd_ha, (nv_offset + i), 
+                       0 /* WRITE operation */) != 0) {
+                       ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
+                               reg + nv_offset + i);
+                       return FAIL_WRITE_FLASH;
+               }
+       }
+
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+               return err;
+       }
+       return (0);
+}
+int
+asd_chk_write_status(struct asd_ha_struct *asd_ha, u32 sector_addr, 
+                       u8 erase_flag) 
+{
+       u32 reg;
+       u32 loop_cnt;
+       u8      nv_data1, nv_data2;
+       u8      toggle_bit1/*, toggle_bit2*/;
+
+       /* 
+        * Read from DQ2 requires sector address 
+        * while it's dont care for DQ6 
+        */
+       /* read_addr = asd->hw_prof.nv_flash_bar + sector_addr;*/
+       reg = asd_ha->hw_prof.flash.bar;
+       loop_cnt = 50000;
+
+       while (loop_cnt) {
+               nv_data1 = asd_read_reg_byte(asd_ha, reg); 
+               nv_data2 = asd_read_reg_byte(asd_ha, reg); 
+
+               toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
+                                ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+               /* toggle_bit2 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ2) 
+                               ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ2));*/
+
+               if (toggle_bit1 == 0) {
+                       return (0);
+               } else {
+                       if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
+                               nv_data1 = asd_read_reg_byte(asd_ha, 
+                                                               reg); 
+                               nv_data2 = asd_read_reg_byte(asd_ha,
+                                                               reg); 
+                               toggle_bit1 = 
+                               ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) 
+                               ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+                               /*
+                               toggle_bit2 = 
+                                  ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ2) 
+                                  ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ2));
+                               */
+                               if (toggle_bit1 == 0) {
+                                       return 0;
+                               }
+                       }
+               }
+               loop_cnt--;
+       
+               /* 
+                * ERASE is a sector-by-sector operation and requires
+                * more time to finish while WRITE is byte-byte-byte
+                * operation and takes lesser time to finish. 
+                *
+                * For some strange reason a reduced ERASE delay gives different
+                * behaviour across different spirit boards. Hence we set
+                * a optimum balance of 50mus for ERASE which works well
+                * across all boards.
+                */ 
+               if (erase_flag) {
+                       udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
+               } else {
+                       udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
+               }
+       }
+       return (-1);
+}
+/*
+ * Function:
+ *     asd_hwi_erase_nv_sector()
+ *
+ * Description:
+ *     Erase the requested NVRAM sector.
+ */
+int
+asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr,u32 size) 
+{
+       u32 reg;
+       u32 sector_addr;
+       reg = asd_ha->hw_prof.flash.bar;
+       /* sector staring address */
+       sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
+       /*
+        * Erasing an NVRAM sector needs to be done in six consecutive
+        * write cyles.
+        */
+       while (sector_addr < flash_addr+size) {
+               switch (asd_ha->hw_prof.flash.method) {
+
+               case FLASH_METHOD_A:
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
+                       asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+                       break;
+
+               case FLASH_METHOD_B:
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
+                       asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+                       asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+                       asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (asd_chk_write_status(asd_ha, sector_addr, 
+                                       1 /* ERASE operation */) != 0) {
+                       return FAIL_ERASE_FLASH;
+               }
+
+               sector_addr += FLASH_SECTOR_SIZE;
+       }
+
+       return (0);
+}
+int asd_check_flash_type(struct asd_ha_struct *asd_ha) 
+{
+       u8 manuf_id;
+       u8 dev_id;
+       u8 sec_prot;
+       u32 inc;
+       u32 reg;
+       int err;
+
+       /* get Flash memory base address */
+       reg = asd_ha->hw_prof.flash.bar;
+
+
+       /* Determine flash info */
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+               return (err);
+       }
+
+       asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
+       asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
+       asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
+
+       /* Get flash info. This would most likely be AMD Am29LV family flash.
+        * First try the sequence for word mode.  It is the same as for
+        * 008B (byte mode only), 160B (word mode) and 800D (word mode).
+        */
+       inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
+       asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
+       asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
+       asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
+       manuf_id = asd_read_reg_byte(asd_ha, reg);
+       dev_id = asd_read_reg_byte(asd_ha,reg+inc);
+       sec_prot = asd_read_reg_byte(asd_ha,reg+inc+inc);
+       /* Get out of autoselect mode. */
+       err = asd_reset_flash(asd_ha);
+       if (err) {
+               ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+               return err;
+       }
+       ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) 
sec_prot(0x%x)\n",manuf_id,dev_id,sec_prot);
+       err = asd_reset_flash(asd_ha);
+       if (err != 0) {
+               return (err);
+       }
+
+       switch (manuf_id) {
+
+       case FLASH_MANUF_ID_AMD:
+
+               switch (sec_prot) {
+
+               case FLASH_DEV_ID_AM29LV800DT:
+               case FLASH_DEV_ID_AM29LV640MT:
+               case FLASH_DEV_ID_AM29F800B:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case FLASH_MANUF_ID_ST:
+
+               switch (sec_prot) {
+
+               case FLASH_DEV_ID_STM29W800DT:
+               case FLASH_DEV_ID_STM29LV640:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case FLASH_MANUF_ID_FUJITSU:
+
+               switch (sec_prot) {
+
+               case FLASH_DEV_ID_MBM29LV800TE:
+               case FLASH_DEV_ID_MBM29DL800TA:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+
+               }
+               break;
+
+       case FLASH_MANUF_ID_MACRONIX:
+
+               switch (sec_prot) {
+
+               case FLASH_DEV_ID_MX29LV800BT:
+                       asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+                       break;
+               }
+               break;
+       }
+
+       if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
+
+               err = asd_reset_flash(asd_ha);
+               if (err) {
+                       ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+                       return err;
+               }
+
+               /* Issue Unlock sequence for AM29LV008BT */
+               asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+               asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+
+               asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
+
+               manuf_id = asd_read_reg_byte(asd_ha, reg);
+               dev_id = asd_read_reg_byte(asd_ha, reg + inc);
+               sec_prot = asd_read_reg_byte(asd_ha, reg + inc+inc);
+
+
+           ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) 
sec_prot(0x%x)\n",manuf_id,dev_id,sec_prot);
+
+               err = asd_reset_flash(asd_ha);
+               if (err != 0) {
+                       ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+                       return (err);
+               }
+
+               switch (manuf_id) {
+               case FLASH_MANUF_ID_AMD:
+
+                       switch (dev_id) {
+
+                       case FLASH_DEV_ID_AM29LV008BT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+
+               case FLASH_MANUF_ID_ST:
+
+                       switch (dev_id) {
+
+                       case FLASH_DEV_ID_STM29008:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+
+               case FLASH_MANUF_ID_FUJITSU:
+
+                       switch (dev_id) {
+
+                       case FLASH_DEV_ID_MBM29LV008TA:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+
+                       }
+                       break;
+
+               case FLASH_MANUF_ID_INTEL:
+
+                       switch (dev_id) {
+
+                       case FLASH_DEV_ID_I28LV00TAT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+
+                       }
+                       break;
+
+               case FLASH_MANUF_ID_MACRONIX:
+
+                       switch (dev_id) {
+
+                       case FLASH_DEV_ID_I28LV00TAT:
+                               asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+                               break;
+
+                       }
+                       break;
+
+               default:
+                       return FAIL_FIND_FLASH_ID;
+               }
+       }
+
+       if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
+             return FAIL_FIND_FLASH_ID;
+
+
+       asd_ha->hw_prof.flash.manuf = manuf_id;
+       asd_ha->hw_prof.flash.dev_id = dev_id;
+       asd_ha->hw_prof.flash.sec_prot = sec_prot;
+       return 0;
+}
diff -urN a/drivers/scsi/aic94xx/aic94xx_sds.h 
b/drivers/scsi/aic94xx/aic94xx_sds.h
--- a/drivers/scsi/aic94xx/aic94xx_sds.h        1969-12-31 16:00:00.000000000 
-0800
+++ b/drivers/scsi/aic94xx/aic94xx_sds.h        2007-10-10 17:16:17.000000000 
-0700
@@ -0,0 +1,168 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Gilbert Wu <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * The aic94xx driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#ifndef _AIC94XX_SDS_H_
+#define _AIC94XX_SDS_H_
+
+enum {
+       FLASH_METHOD_UNKNOWN,
+       FLASH_METHOD_A,
+       FLASH_METHOD_B
+};
+
+#define FLASH_MANUF_ID_AMD              0x01
+#define FLASH_MANUF_ID_ST               0x20
+#define FLASH_MANUF_ID_FUJITSU          0x04
+#define FLASH_MANUF_ID_MACRONIX         0xC2
+#define FLASH_MANUF_ID_INTEL            0x89
+#define FLASH_MANUF_ID_UNKNOWN          0xFF
+
+#define FLASH_DEV_ID_AM29LV008BT        0x3E
+#define FLASH_DEV_ID_AM29LV800DT        0xDA
+#define FLASH_DEV_ID_STM29W800DT        0xD7
+#define FLASH_DEV_ID_STM29LV640         0xDE
+#define FLASH_DEV_ID_STM29008           0xEA
+#define FLASH_DEV_ID_MBM29LV800TE       0xDA
+#define FLASH_DEV_ID_MBM29DL800TA       0x4A
+#define FLASH_DEV_ID_MBM29LV008TA       0x3E
+#define FLASH_DEV_ID_AM29LV640MT        0x7E
+#define FLASH_DEV_ID_AM29F800B          0xD6
+#define FLASH_DEV_ID_MX29LV800BT        0xDA
+#define FLASH_DEV_ID_MX29LV008CT        0xDA
+#define FLASH_DEV_ID_I28LV00TAT         0x3E
+#define FLASH_DEV_ID_UNKNOWN            0xFF
+/* status bit mask values */
+#define FLASH_STATUS_BIT_MASK_DQ6       0x40
+#define FLASH_STATUS_BIT_MASK_DQ5       0x20
+#define FLASH_STATUS_BIT_MASK_DQ2       0x04
+/* minimum value in micro seconds needed for checking status */
+#define FLASH_STATUS_ERASE_DELAY_COUNT  50
+#define FLASH_STATUS_WRITE_DELAY_COUNT  25
+
+#define FLASH_SECTOR_SIZE               0x010000
+#define FLASH_SECTOR_SIZE_MASK          0xffff0000
+
+
+
+#define FLASH_OK                        0x000000
+#define FAIL_OPEN_BIOS_FILE             0x000100
+#define FAIL_CHECK_PCI_ID               0x000200
+#define FAIL_CHECK_SUM                  0x000300
+#define FAIL_UNKNOWN                    0x000400
+#define FAIL_VERIFY                     0x000500
+#define FAIL_RESET_FLASH                0x000600
+#define FAIL_FIND_FLASH_ID              0x000700
+#define FAIL_ERASE_FLASH                0x000800
+#define FAIL_WRITE_FLASH                0x000900
+#define FAIL_FILE_SIZE                  0x000a00
+#define FAIL_PARAMETERS                 0x000b00
+#define FAIL_OUT_MEMORY                 0x000c00
+#define FLASH_IN_PROGRESS               0x001000
+
+
+struct controller_id
+{
+    u32 vendor;
+    /* PCI Vendor ID */
+
+    u32 device;
+    /* PCI Device ID */
+
+    u32 sub_vendor;
+    /* PCI Subvendor ID */
+
+    u32 sub_device;
+    /* PCI Subdevice ID */
+
+};
+struct image_info
+{
+       u32 ImageId;            
+       /*Identifies the image(e.g 0=Footbridge image,1=Drawbridge image)*/
+
+       u32 ImageOffset;        
+       /*Offset of the image from the beginning of the file*/
+
+       u32 ImageLength;        
+       /*length of the image*/
+
+       u32 ImageChecksum;
+       /*Image checksum*/
+
+       u32 ImageVersion;       
+       /*Version of the image, could be build number*/
+};
+
+struct bios_file_header
+{
+       u8 signature[32];       
+       /* Signature/Cookie to identify the file*/
+       /* The signature above is only 25 characters long.  The program will 
insert a
+       Build Number and a ^Z to the end of the string, so that a user can 
issue the
+       DOS type command against the file and have the signature displayed to 
identify
+       the file.  */
+
+       u32 checksum;           
+       /*Entire file checksum with this field zero*/
+
+       u32 antidote;
+       /*Entire file checksum antidote with this field 0xFFFFFFFF*/
+
+       struct controller_id contrl_id;
+       /*Controller id to identify the controller whose images are*/
+       /*stored in the file.  */
+
+       u32 filelen;            
+       /*Length of the entire file*/
+
+       u32 chunk_num;          
+       /*The chunk/part number of this DOS file in case the Image */
+       /*is stored in parts in multiple DOS files across floppies*/
+
+       u32 total_chunks;       
+       /*Total number of chunks/parts in which the image file is stored*/
+
+       u32 num_images;         
+       /*Number of images in the file,e.g Footbridge image, Drawbridge image*/
+
+       u32 build_num;
+       /*Build number of the process that generated this image*/
+
+       struct image_info image_header;
+};
+
+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, 
+               void *src,u32 dest_offset, u32 bytes_to_verify);
+int asd_write_flash_seg(struct asd_ha_struct *asd_ha, 
+               void *src,u32 dest_offset, u32 bytes_to_write);
+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
+               u32 sector_addr, u8 erase_flag);
+int asd_check_flash_type(struct asd_ha_struct *asd_ha);
+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr,u32 
size); 
+#endif
+
+
+
+

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to