All pastes #539875 Raw Edit

Something

public text v1 · immutable
·published 2007-06-05 11:54 UTC
rendered paste body
#include "flash.h"

#include "debug.h"
#include "hv.h"
#include "time.h"

/* flash device only allows 256K writes */
#define FLASH_WRITE_UNIT (256*1024)

static __inline__ int check_otheros_flash(unsigned char *buf)
{
  int i;
  for(i=0; i<16; i++)
    if(buf[i] != "cell_ext_os_area"[i])
      return 0;
  return *(int *)(buf+16) == 1;
}

static int wait_for_io(unsigned long device_id, unsigned long tag,
		       unsigned long *status, unsigned long timeout)
{
  unsigned long rtag;
  long r;
  for(;;) {
    r = lv1_storage_get_async_status(device_id, &rtag, status);
    if(!r && rtag == tag)
      return 1;
    if(!timeout) {
      DBG(" TIMEOUT ");
      break;
    } else if(timeout > 25000) {
      usleep(25000);
      timeout -= 25000;
    } else {
      usleep(timeout);
      timeout = 0;
    }
  }
  return 0;
}

int set_boot_flag(int boot_flag)
{
  long r;
  unsigned long v1, v2, ndev, nreg, blk_size, nblks, dma_addr, tag, status;
  int bus_index;
  unsigned long dev_index, reg_index;
  unsigned long bus_id, device_id, region_id;
  static unsigned char buf[FLASH_WRITE_UNIT] __attribute__((section(".bss.page_aligned")));
  int rc = 0;

  /* Find storage bus */
  for(bus_index=0; bus_index<128; bus_index++) {
    r = lv1_get_repository_node_value(1,
				      0x0000000062757300+bus_index, /* "bus" */
				      0x7479706500000000, /* "type" */
				      0, 0, &v1, &v2);
    if(r)
      return 0;
    if(v1 != 5 /* storage type */)
      continue;

    r = lv1_get_repository_node_value(1,
				      0x0000000062757300+bus_index, /* "bus" */
				      0x6964000000000000, /* "id" */
				      0, 0, &v1, &v2);
    if(r)
      return 0;
    bus_id = v1;

    r = lv1_get_repository_node_value(1,
				      0x0000000062757300+bus_index, /* "bus" */
				      0x6e756d5f64657600, /* "num_dev" */
				      0, 0, &v1, &v2);
    if(r)
      return 0;
    ndev = v1;

    /* Look for flash devices */
    for(dev_index=0; dev_index<ndev; dev_index++) {
      r = lv1_get_repository_node_value(1,
					0x0000000062757300+bus_index, /* "bus" */
					0x6465760000000000+dev_index, /* "dev" */
					0x7479706500000000, /* "type" */
					0, &v1, &v2);
      if(r)
	return 0;
      if(v1 != 14 /* SCSI device type for RBC */)
	continue;

      r = lv1_get_repository_node_value(1,
					0x0000000062757300+bus_index, /* "bus" */
					0x6465760000000000+dev_index, /* "dev" */
					0x626c6b5f73697a65, /* "blk_size" */
					0, &v1, &v2);
      if(r)
	return 0;
      blk_size = v1;
      if(blk_size < 1 || blk_size > sizeof(buf))
	continue;

      nblks = sizeof(buf)/blk_size;

      r = lv1_get_repository_node_value(1,
					0x0000000062757300+bus_index, /* "bus" */
					0x6465760000000000+dev_index, /* "dev" */
					0x6964000000000000, /* "id" */
					0, &v1, &v2);
      device_id = v1;

      r = lv1_get_repository_node_value(1,
					0x0000000062757300+bus_index, /* "bus" */
					0x6465760000000000+dev_index, /* "dev" */
					0x6e5f726567730000, /* "n_regs" */
					0, &v1, &v2);
      if(r)
	return 0;
      nreg = v1;

      r = lv1_open_device(bus_id, device_id, 0);
      if(r)
	continue;

      r = lv1_allocate_device_dma_region(bus_id, device_id,
					 128*1024*1024, 12, 0, &dma_addr);
      if(r) {
	lv1_close_device(bus_id, device_id);
	continue;
      }

      r = lv1_map_device_dma_region(bus_id, device_id, 0, dma_addr,
				    128*1024*1024, 0xf800000000000000UL);
      if(r) {
	lv1_free_device_dma_region(bus_id, device_id, dma_addr);
	lv1_close_device(bus_id, device_id);
	continue;
      }

      for(reg_index=0; reg_index<nreg; reg_index++) {
	r = lv1_get_repository_node_value(1,
					  0x0000000062757300+bus_index, /* "bus" */
					  0x6465760000000000+dev_index, /* "dev" */
					  0x726567696f6e0000+reg_index, /* "region" */
					  0x6964000000000000, /* "id" */
					  &v1, &v2);
	if(r)
	  continue;
	region_id = v1;

	r = lv1_storage_read(device_id, region_id, 0, nblks, 0,
			     (unsigned long)buf, &tag);
	if(r)
	  continue;

	if(!wait_for_io(device_id, tag, &status, 1000000) ||
	   status != 0)
	  continue;

	if(!check_otheros_flash(buf))
	  continue;

	rc = -1;

	/* Set boot flag */
	buf[0x203] = boot_flag;

	DBG("lv1_storage_write(%lx, %lx, 0, %lx, 0, %p, %p)",
	    device_id, region_id, nblks, buf, &tag);
	r = lv1_storage_write(device_id, region_id, 0, nblks, 0,
			      (unsigned long)buf, &tag);
	DBG("storage_write => %ld [%lx]\n", r, tag);
	if(r)
	  break;

	if(!wait_for_io(device_id, tag, &status, 5000000) ||
	   status != 0)
	  break;
	
	DBG("Bootflag successfully set to %d!\n", boot_flag);
	rc = 1;
	break;
      }

      lv1_unmap_device_dma_region(bus_id, device_id, dma_addr, 128*1024*1024);
      lv1_free_device_dma_region(bus_id, device_id, dma_addr);
      lv1_close_device(bus_id, device_id);
      if(rc)
	return rc;
    }
  }
  return 0;
}