booting OSX problems...

Bill Mueller mol-general@lists.maconlinux.org
Thu, 12 Sep 2002 17:45:30 -0700


As unproffessionally as possible I added the printm statements, and it looks
like it is never getting the ablk semiphore (ablk)  I posted the edited file
at the end of the message.

The output loops as below untill it hangs:

point A
point b
point k
point b
point f
point b
point C
point j
point d
...

Any suggested fixes?
-Bill

**** start ablk.c *****
#include "mol_config.h"
#include <sys/uio.h>
#include <sys/resource.h>
#include <semaphore.h>
#include "prom.h"
#include "os_interface.h"
#include "disk.h"
#include "promif.h"
#include "disk.h"
#include "driver_mgr.h"
#include "memory.h"
#include "llseek.h"
#include "pic.h"
#include "mac_registers.h"
#include "thread.h"
#include "ablk_sh.h"
#include "timer.h"
#include "partition_table.h"

//#include <sched.h>

typedef struct {
 int  id;
 bdev_desc_t *bdev;
 int  hardsect;  /* Hardsector size */
 int  ablk_flags;
} ablk_device_t;

typedef struct {
 int  irq;
 int  ndevs;
 ablk_device_t *devs;   /* array with ndevs elements */

 /* channel */
 int  running;  /* ready for action */
 int  active;   /* read thread is active */
 sem_t  sem;
 int  exiting;

 /* request ring */
 int  req_head;  /* index of head element in ring */
 int  ring_mask;  /* ring index mask */
 ablk_req_head_t *ring;

 /* fields private to the i/o thread */
 int  n_requests;  /* #descriptors processed (used for completion) */
 int  cur_fd;
 int   (*iofunc)( int, const struct iovec*, int count );
} ablk_t;

static ablk_t  ablk;


/************************************************************************/
/* OSI interface       */
/************************************************************************/

#define MAX_IOVEC 32

static int
dummy_io( int fd, const struct iovec *vec, int n )
{
 int i, s;

 for( s=0, i=0; i<n; i++ )
  s += vec[i].iov_len;

 //printm("dummy_io: [%d] %d bytes\n", fd, s );
 return s;
}


#define NEXT(ind) (((ind)+1) & ablk.ring_mask)

static void
do_work( void )
{
 struct iovec vec[MAX_IOVEC];
 int n, count;

 n = count = 0;

//EDIT ***********************************
 printm("point A\n");

 for( ;; ) {
  ablk_req_head_t *cur = &ablk.ring[ ablk.req_head ];
  int proceed = cur->proceed;
  int next = NEXT( ablk.req_head );
  ablk_req_head_t *r = &ablk.ring[next];
  int f;

  //EDIT******************************
  printm("point B\n");

  /* execute request? */
  if( n && (!proceed || n == MAX_IOVEC || !(r->flags & ABLK_SG_BUF)) ) {
   int raise_irq = cur->flags & ABLK_RAISE_IRQ;

//EDIT *****************************
   printm("point C\n");

   if( (*ablk.iofunc)( ablk.cur_fd, vec, n ) != count )
    goto error;
   /* dummy_io( ablk.cur_fd, vec, n ); */

   ablk.n_requests += n;
   /* printm("__completion: %d\n", ablk.n_requests ); */

   /* this takes into account the engine stall interrupt */
   if( raise_irq && proceed )
    irq_line_hi( ablk.irq );
   n = 0;
  }
  /* engine stall? */
  if( !proceed )
   break;

  /* flag old head slot for reuse */
  cur->flags = 0;

  /* advance pointer to next request */
  cur->proceed = 0;
  f = r->flags;
  ablk.req_head = next;

  /* process scatter & gather bufs */
  if( (f & ABLK_SG_BUF) ) {
   ablk_sg_t *p = (ablk_sg_t*)r;

   //EDIT ********************************
   printm("point f\n");

   if( mphys_to_lvptr( p->buf, (char**)&vec[n].iov_base ) )
    goto error;
   vec[n++].iov_len = p->count;
   count += p->count;

   /* req_count is increased when the request is finished */
   continue;
  }

  /* no-op request (used primarily for error abort) */
  if( (f & ABLK_NOP_REQ) ) {
   ablk.iofunc = dummy_io;
   ablk.cur_fd = -1;

   //EDIT ******************************
   printm("point h\n");

   irq_line_hi( ablk.irq );

   ablk.n_requests++;
   continue;
  }

  /* must be a read/write request */
  ablk.iofunc = (f & ABLK_WRITE_REQ) ? &writev : &readv;
  //ablk.iofunc = (f & ABLK_WRITE_REQ) ? &dummy_io : &readv;

  if( (unsigned int)r->unit > ablk.ndevs )
   goto error;
  ablk.cur_fd = ablk.devs[r->unit].bdev->fd;

  //EDIT**************************
  printm("point k\n");

  if( blk_lseek( ablk.cur_fd, r->sector, 0 ) < 0 )
   goto error;

  count = 0;
  ablk.n_requests++;
 }

 /* engine stall */
 ablk.active = 0;

 // EDIT ************************
 printm("point j\n");
 irq_line_hi( ablk.irq );

 return;

 error:
 printm("ABlk engine error\n");
 ablk.running = 0;
 ablk.active = 0;

 irq_line_hi( ablk.irq );
}

static void
io_thread( void *dummy )
{
#if 1
 setpriority( PRIO_PROCESS, getpid(), -19 );
#else
 struct sched_param shp;
 memset( &shp, 0, sizeof(shp) );

 shp.sched_priority = 1;
 if( sched_setscheduler( getpid(), SCHED_FIFO, &shp ) < 0 )
  perrorm("sched_setscheduler");
#endif
 for( ;; ) {

//EDIT *****************************************
  printm("Point D");

sem_wait( &ablk.sem );
  if( ablk.exiting )
   break;
  do_work();
 }
}


/* kick( channel ) */
static int
osip_ablk_kick( int sel, int *params )
{
 int channel = params[0];

 if( channel )
  return -1;
 if( ablk.active )
  return 0;

 ablk.active = 1;
 sem_post( &ablk.sem );
 return 0;
}

/* ablk_irq_ack( channel, &request_count ) */
static int
osip_ablk_irq_ack( int sel, int *params )
{
 int channel = params[0];
 if( channel )
  return -1;

 /* It is legal to call this function with a stopped channel
  * in order to obtain the request count.
  *
  * The client only needs to call kick if we return 0; this is atomic
  * since the i/o thread clears the active field before the interrupt
  * is raised.
  */
 irq_line_low( ablk.irq );

 /* restart engine if there is work to do */
 if( !ablk.active && ablk.running && ablk.ring[ablk.req_head].proceed )
  osip_ablk_kick( sel, params );

 mregs->gpr[4] = ablk.n_requests;
 return ablk.active;
}

/* setup_ring( channel, mphys, n_el ) */
static int
osip_ablk_ring_setup( int sel, int *params )
{
 int channel = params[0];
 int mphys = params[1];
 int mask = params[2]-1;
 char *lvptr;

 if( channel )
  return -1;
 if( ablk.running || ((mask+1) & mask) || mphys_to_lvptr(mphys, &lvptr) )
  return -1;

 ablk.ring_mask = mask;
 ablk.ring = (ablk_req_head_t*)lvptr;
 return 0;
}

/* cntrl( int channel, int cmd ) */
static int
osip_ablk_cntrl( int sel, int *params )
{
 int channel = params[0];
 int ret = 0;

 if( channel )
  return -1;

 switch( params[1] ) {
 case kABlkStart:
  if( ablk.running )
   break;

  ablk.cur_fd = -1;
  ablk.iofunc = dummy_io;
  if( ablk.ring ) {
   /* el. 1 is the first element to be processed */
   ablk.req_head = 0;
   ablk.ring[0].flags = ABLK_NOP_REQ;

   ablk.n_requests = 0;
   ablk.running = 1;
  } else
   ret = -1;
  break;

 default:
  printm("Bad ablk request\n");
  ret = -1;
  /* fall through */
 case kABlkReset:
  ablk.n_requests = 0;
  /* fall through */
 case kABlkStop:
  if( ablk.active ) {
   /* XXX: wait for thread to terminate */
  }
  ablk.running = 0;
  break;
 }
 if( !ablk.running )
  irq_line_low( ablk.irq );

 return ret;
}

/* disk_info( channel, index ). Info struct return in r4-r7 */
static int
osip_ablk_disk_info( int sel, int *params )
{
 int channel = params[0];
 uint index = params[1];
 ablk_device_t *d = &ablk.devs[index];
 ablk_disk_info_t info;

 if( channel )
  return -1;
 if( index >= ablk.ndevs )
  return -1;

 info.nblks = d->bdev->size / 512; /* XXX fix sector size */
 info.flags = d->ablk_flags;
 info.res1 = info.res2 = 0;

 /* Return ablk_disk_info_t in r4-r5 */
 *(ablk_disk_info_t*)&mregs->gpr[4] = info;
 return 0;
}

/************************************************************************/
/* Synchronous IO (for boot loaders)    */
/************************************************************************/

/* sync_io( int channel, int unit, int blk, ulong mphys, int size ) */
static int
osip_ablk_sync_io( int sel, int *params )
{
 int channel = params[0];
 uint ind = params[1];
 int blk = params[2];
 ulong mphys = params[3];
 int size = params[4];
        ablk_device_t *d = &ablk.devs[ind];
 char *buf;

 if( channel || ind > ablk.ndevs || ablk.running || mphys_to_lvptr( mphys,
&buf ) )
  return -1;
 if( blk_lseek( d->bdev->fd, blk, 0 ) < 0 )
  return -1;
 if( sel == OSI_ABLK_SYNC_WRITE ) {
  printm("sync write unimplemented\n");
  return -1;
 }
 if( read( d->bdev->fd, buf, size ) != size )
  return -1;

 return 0;
}


/************************************************************************/
/* Init / Cleanup       */
/************************************************************************/

static void
add_drive( mol_device_node_t *dn, bdev_desc_t *bdev )
{
 desc_map_t dmap;
 ablk_device_t *d;
 int i, unit, is_boot;

 d = realloc( ablk.devs, sizeof(ablk_device_t) * (ablk.ndevs+1) );
 fail_nil( d );

 ablk.devs = d;
 unit = ablk.ndevs++;
 d = &ablk.devs[unit];

 d->bdev = bdev;
 d->hardsect = 512;
 d->ablk_flags = (bdev->flags & BF_ENABLE_WRITE) ? 0 : ABLK_INFO_READ_ONLY;

 /* check if there are partitions */
 lseek( bdev->fd, 0, SEEK_SET );
 read( bdev->fd, &dmap, sizeof(dmap) );
 if( dmap.sbSig == DESC_MAP_SIGNATURE )
  d->ablk_flags |= ABLK_HAS_PARTABLE;

 is_boot = (bdev->flags & BF_BOOT);
 for( i=0; is_boot && i<unit; i++ )
  if( (ablk.devs[i].bdev->flags & BF_BOOT) ) {
   is_boot = 0;
   printm("Warning: Multiple boot volumes specified\n");
  }

 /* set the /chosen/rootpath property in the device tree */
 if( is_boot ) {
  mol_device_node_t *chosen;
  char buf[128];

  snprintf( buf, sizeof(buf), "%s/disk@%x:%d", dn->full_name, unit, 0 );
  printm("Boot device: %s\n", buf );
  if( (chosen=prom_find_dev_by_path("/chosen")) )
   prom_add_property( chosen, "boot-device", buf, strlen(buf)+1 );
 }
}

static int
ablk_init( void )
{
 bdev_desc_t *bdev;
 mol_device_node_t *dn;

 memset( &ablk, 0, sizeof(ablk) );
 if( !(dn=prom_find_devices("mol-blk")) || prom_get_int_property(dn,
"mol-irq", &ablk.irq) )
  return 0;

 while( (bdev=bdev_get_volume(BDEV_TYPE_ANY)) )
  add_drive( dn, bdev );

 sem_init( &ablk.sem, 0, 0 );
 create_thread( io_thread, NULL, "blk-io" );

 os_interface_add_proc( OSI_ABLK_RING_SETUP, osip_ablk_ring_setup );
 os_interface_add_proc( OSI_ABLK_CNTRL, osip_ablk_cntrl );
 os_interface_add_proc( OSI_ABLK_DISK_INFO, osip_ablk_disk_info );
 os_interface_add_proc( OSI_ABLK_KICK, osip_ablk_kick );
 os_interface_add_proc( OSI_ABLK_IRQ_ACK, osip_ablk_irq_ack );
 os_interface_add_proc( OSI_ABLK_SYNC_READ, osip_ablk_sync_io );
 os_interface_add_proc( OSI_ABLK_SYNC_WRITE, osip_ablk_sync_io );

 return 1;
}

static void
ablk_cleanup( void )
{
 int i;

 ablk.exiting = 1;
 sem_post( &ablk.sem );
 sem_destroy( &ablk.sem );

 for( i=0; i<ablk.ndevs; i++ )
  bdev_close_volume( ablk.devs[i].bdev );

 free( ablk.devs );
 ablk.ndevs = 0;
}

driver_interface_t ablk_driver = {
 "ablk", ablk_init, ablk_cleanup
};