1. Create a file "update_bios" in sysfs to allow user to update bios from user space. 2. The 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 <gilbert_wu@xxxxxxxxxxx> 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 <gilbert_wu@xxxxxxxxxxx> + * + * 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html