aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx/aic94xx_init.c
diff options
context:
space:
mode:
authorGilbert Wu <Gilbert_Wu@adaptec.com>2007-10-22 18:19:11 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:22:30 -0500
commit1237c98db2aa94b42dbb9fb1df062b7d3733dc83 (patch)
tree01c6d82790815753c0e66e9c3e571862d0f226bf /drivers/scsi/aic94xx/aic94xx_init.c
parent285e9670d91cdeb6b6693729950339cb45410fdc (diff)
[SCSI] aic94xx: update BIOS image from user space.
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@adaptec.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/aic94xx/aic94xx_init.c')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index b70d6e7f96e9..de0667011e13 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -29,6 +29,7 @@
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/pci.h> 30#include <linux/pci.h>
31#include <linux/delay.h> 31#include <linux/delay.h>
32#include <linux/firmware.h>
32 33
33#include <scsi/scsi_host.h> 34#include <scsi/scsi_host.h>
34 35
@@ -36,6 +37,7 @@
36#include "aic94xx_reg.h" 37#include "aic94xx_reg.h"
37#include "aic94xx_hwi.h" 38#include "aic94xx_hwi.h"
38#include "aic94xx_seq.h" 39#include "aic94xx_seq.h"
40#include "aic94xx_sds.h"
39 41
40/* The format is "version.release.patchlevel" */ 42/* The format is "version.release.patchlevel" */
41#define ASD_DRIVER_VERSION "1.0.3" 43#define ASD_DRIVER_VERSION "1.0.3"
@@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
313} 315}
314static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); 316static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
315 317
318#define FLASH_CMD_NONE 0x00
319#define FLASH_CMD_UPDATE 0x01
320#define FLASH_CMD_VERIFY 0x02
321
322struct flash_command {
323 u8 command[8];
324 int code;
325};
326
327static struct flash_command flash_command_table[] =
328{
329 {"verify", FLASH_CMD_VERIFY},
330 {"update", FLASH_CMD_UPDATE},
331 {"", FLASH_CMD_NONE} /* Last entry should be NULL. */
332};
333
334struct error_bios {
335 char *reason;
336 int err_code;
337};
338
339static struct error_bios flash_error_table[] =
340{
341 {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE},
342 {"PCI ID mismatch", FAIL_CHECK_PCI_ID},
343 {"Checksum mismatch", FAIL_CHECK_SUM},
344 {"Unknown Error", FAIL_UNKNOWN},
345 {"Failed to verify.", FAIL_VERIFY},
346 {"Failed to reset flash chip.", FAIL_RESET_FLASH},
347 {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID},
348 {"Failed to erash flash chip.", FAIL_ERASE_FLASH},
349 {"Failed to program flash chip.", FAIL_WRITE_FLASH},
350 {"Flash in progress", FLASH_IN_PROGRESS},
351 {"Image file size Error", FAIL_FILE_SIZE},
352 {"Input parameter error", FAIL_PARAMETERS},
353 {"Out of memory", FAIL_OUT_MEMORY},
354 {"OK", 0} /* Last entry err_code = 0. */
355};
356
357static ssize_t asd_store_update_bios(struct device *dev,
358 struct device_attribute *attr,
359 const char *buf, size_t count)
360{
361 struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
362 char *cmd_ptr, *filename_ptr;
363 struct bios_file_header header, *hdr_ptr;
364 int res, i;
365 u32 csum = 0;
366 int flash_command = FLASH_CMD_NONE;
367 int err = 0;
368
369 cmd_ptr = kzalloc(count*2, GFP_KERNEL);
370
371 if (!cmd_ptr) {
372 err = FAIL_OUT_MEMORY;
373 goto out;
374 }
375
376 filename_ptr = cmd_ptr + count;
377 res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
378 if (res != 2) {
379 err = FAIL_PARAMETERS;
380 goto out1;
381 }
382
383 for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
384 if (!memcmp(flash_command_table[i].command,
385 cmd_ptr, strlen(cmd_ptr))) {
386 flash_command = flash_command_table[i].code;
387 break;
388 }
389 }
390 if (flash_command == FLASH_CMD_NONE) {
391 err = FAIL_PARAMETERS;
392 goto out1;
393 }
394
395 if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
396 err = FLASH_IN_PROGRESS;
397 goto out1;
398 }
399 err = request_firmware(&asd_ha->bios_image,
400 filename_ptr,
401 &asd_ha->pcidev->dev);
402 if (err) {
403 asd_printk("Failed to load bios image file %s, error %d\n",
404 filename_ptr, err);
405 err = FAIL_OPEN_BIOS_FILE;
406 goto out1;
407 }
408
409 hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
410
411 if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
412 hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
413 (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
414 hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
415
416 ASD_DPRINTK("The PCI vendor or device id does not match\n");
417 ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
418 " pci vendor=%x pci dev=%x\n",
419 hdr_ptr->contrl_id.vendor,
420 hdr_ptr->contrl_id.device,
421 hdr_ptr->contrl_id.sub_vendor,
422 hdr_ptr->contrl_id.sub_device,
423 asd_ha->pcidev->vendor,
424 asd_ha->pcidev->device);
425 err = FAIL_CHECK_PCI_ID;
426 goto out2;
427 }
428
429 if (hdr_ptr->filelen != asd_ha->bios_image->size) {
430 err = FAIL_FILE_SIZE;
431 goto out2;
432 }
433
434 /* calculate checksum */
435 for (i = 0; i < hdr_ptr->filelen; i++)
436 csum += asd_ha->bios_image->data[i];
437
438 if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
439 ASD_DPRINTK("BIOS file checksum mismatch\n");
440 err = FAIL_CHECK_SUM;
441 goto out2;
442 }
443 if (flash_command == FLASH_CMD_UPDATE) {
444 asd_ha->bios_status = FLASH_IN_PROGRESS;
445 err = asd_write_flash_seg(asd_ha,
446 &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
447 0, hdr_ptr->filelen-sizeof(*hdr_ptr));
448 if (!err)
449 err = asd_verify_flash_seg(asd_ha,
450 &asd_ha->bios_image->data[sizeof(*hdr_ptr)],
451 0, hdr_ptr->filelen-sizeof(*hdr_ptr));
452 } else {
453 asd_ha->bios_status = FLASH_IN_PROGRESS;
454 err = asd_verify_flash_seg(asd_ha,
455 &asd_ha->bios_image->data[sizeof(header)],
456 0, hdr_ptr->filelen-sizeof(header));
457 }
458
459out2:
460 release_firmware(asd_ha->bios_image);
461out1:
462 kfree(cmd_ptr);
463out:
464 asd_ha->bios_status = err;
465
466 if (!err)
467 return count;
468 else
469 return -err;
470}
471
472static ssize_t asd_show_update_bios(struct device *dev,
473 struct device_attribute *attr, char *buf)
474{
475 int i;
476 struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
477
478 for (i = 0; flash_error_table[i].err_code != 0; i++) {
479 if (flash_error_table[i].err_code == asd_ha->bios_status)
480 break;
481 }
482 if (asd_ha->bios_status != FLASH_IN_PROGRESS)
483 asd_ha->bios_status = FLASH_OK;
484
485 return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
486 flash_error_table[i].err_code,
487 flash_error_table[i].reason);
488}
489
490static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
491 asd_show_update_bios, asd_store_update_bios);
492
316static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) 493static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
317{ 494{
318 int err; 495 int err;
@@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
328 err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); 505 err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
329 if (err) 506 if (err)
330 goto err_biosb; 507 goto err_biosb;
508 err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
509 if (err)
510 goto err_update_bios;
331 511
332 return 0; 512 return 0;
333 513
514err_update_bios:
515 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
334err_biosb: 516err_biosb:
335 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); 517 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
336err_rev: 518err_rev:
@@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
343 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); 525 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
344 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); 526 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
345 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); 527 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
528 device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
346} 529}
347 530
348/* The first entry, 0, is used for dynamic ids, the rest for devices 531/* The first entry, 0, is used for dynamic ids, the rest for devices
@@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
589 asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; 772 asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
590 asd_ha->sas_ha.lldd_ha = asd_ha; 773 asd_ha->sas_ha.lldd_ha = asd_ha;
591 774
775 asd_ha->bios_status = FLASH_OK;
592 asd_ha->name = asd_dev->name; 776 asd_ha->name = asd_dev->name;
593 asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); 777 asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
594 778