Gilbert Wu wrote: > 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 > @@ -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); cmd_ptr = kzalloc(count * 2, GFP_KERNEL); > + 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))) { ^ Space missing > + 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, ^ Superfluous whitespace > + 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)); ^ This comma belongs in the last line. > + if (!err) { > + err = > asd_verify_flash_seg(asd_ha,&asd_ha->bios_image->data[sizeof(*hdr_ptr)] > + ,0,hdr_ptr->filelen-sizeof(*hdr_ptr)); ^ This one too. > + } > + } > + 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 It's rather obvious what kfree() does, isn't it? > 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" I prefer a newline before this comment. YMMV. > /* ---------- 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. > + */ Kernel-doc description? /** * asd_hwi_write_nv_segment - Writes data to an NVRAM segment * @asd_ha: ... > +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); 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); ^^ flash, I'd prefer whitespace before the number. In this form someone could think it's a flash index and not the error code on the first look. > + 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); ^ Whitespace, too. > + 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) { Putting the comment on an own line would make it more readable IMHO. > + 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 Empty line between functions missing. More of this on other places. > +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) { for-loop? > + 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); 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); return -1; > +} > +/* > + * Function: > + * asd_hwi_erase_nv_sector() > + * > + * Description: > + * Erase the requested NVRAM sector. > + */ Kerneldoc again? > +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); return 0; Greetings, Eike
Attachment:
signature.asc
Description: This is a digitally signed message part.