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
};