Charles.Forsyth20080611-1520578fdae18 years agoHistory
631 lines · 11.2 KB · C
RawDownload
/* * Storage Device. */#include "u.h"#include "mem.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "error.h" #include "sd.h"#include "fs.h" #define parttrace 0  extern SDifc* sdifc[]; static SDev* sdlist;static SDunit** sdunit;static int sdnunit;static int _sdmask;static int cdmask;static int sdmask; enum {	Rawcmd,	Rawdata,	Rawstatus,}; voidsdaddpart(SDunit* unit, char* name, uvlong start, uvlong end){	SDpart *pp;	int i, partno; 	if(parttrace)		print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);	/*	 * Check name not already used	 * and look for a free slot.	 */	if(unit->part != nil){		partno = -1;		for(i = 0; i < SDnpart; i++){			pp = &unit->part[i];			if(!pp->valid){				if(partno == -1)					partno = i;				break;			}			if(strcmp(name, pp->name) == 0){				if(pp->start == start && pp->end == end){					if(parttrace)						print("already present\n");					return;				}			}		}	}else{		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){			if(parttrace)				print("malloc failed\n");			return;		}		partno = 0;	} 	/*	 * Check there is a free slot and size and extent are valid.	 */	if(partno == -1 || start > end || end > unit->sectors){		print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",			unit->name, name, start, end, unit->sectors, 			partno==-1 ? "no free partitions" : "partition boundaries out of range");		return;	}	pp = &unit->part[partno];	pp->start = start;	pp->end = end;	strncpy(pp->name, name, NAMELEN);	pp->valid = 1;	unit->npart++;} voidsddelpart(SDunit* unit,  char* name){	int i;	SDpart *pp; 	if(parttrace)		print("del %d %s %s\n", unit->npart, unit->name, name);	/*	 * Look for the partition to delete.	 * Can't delete if someone still has it open.	 * If it's the last valid partition zap the	 * whole table.	 */	pp = unit->part;	for(i = 0; i < SDnpart; i++){		if(strncmp(name, pp->name, NAMELEN) == 0)			break;		pp++;	}	if(i >= SDnpart)		return;	pp->valid = 0; 	unit->npart--;	if(unit->npart == 0){		free(unit->part);		unit->part = nil;	}} static intsdinitpart(SDunit* unit){	unit->sectors = unit->secsize = 0;	unit->npart = 0;	if(unit->part){		free(unit->part);		unit->part = nil;	} 	if(unit->inquiry[0] & 0xC0)		return 0;	switch(unit->inquiry[0] & 0x1F){	case 0x00:			/* DA */	case 0x04:			/* WORM */	case 0x05:			/* CD-ROM */	case 0x07:			/* MO */		break;	default:		return 0;	} 	if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0)		return 0;	sdaddpart(unit, "data", 0, unit->sectors);	return 1;} static SDunit*sdgetunit(SDev* sdev, int subno){	int index;	SDunit *unit; 	/*	 * Associate a unit with a given device and sub-unit	 * number on that device.	 * The device will be probed if it has not already been	 * successfully accessed.	 */	qlock(&sdqlock);	index = sdev->index+subno;	unit = sdunit[index];	if(unit == nil){		if((unit = malloc(sizeof(SDunit))) == nil){			qunlock(&sdqlock);			return nil;		} 		if(sdev->enabled == 0 && sdev->ifc->enable)			sdev->ifc->enable(sdev);		sdev->enabled = 1; 		snprint(unit->name, NAMELEN, "sd%c%d", sdev->idno, subno);		unit->subno = subno;		unit->dev = sdev; 		/*		 * No need to lock anything here as this is only		 * called before the unit is made available in the		 * sdunit[] array.		 */		if(unit->dev->ifc->verify(unit) == 0){			qunlock(&sdqlock);			free(unit);			return nil;		}		sdunit[index] = unit;	}	qunlock(&sdqlock); 	return unit;} static SDunit*sdindex2unit(int index){	SDev *sdev; 	/*	 * Associate a unit with a given index into the top-level	 * device directory.	 * The device will be probed if it has not already been	 * successfully accessed.	 */	for(sdev = sdlist; sdev != nil; sdev = sdev->next){		if(index >= sdev->index && index < sdev->index+sdev->nunit)			return sdgetunit(sdev, index-sdev->index);	} 	return nil;} static void_sddetach(void){	SDev *sdev; 	for(sdev = sdlist; sdev != nil; sdev = sdev->next){		if(sdev->enabled == 0)			continue;		if(sdev->ifc->disable)			sdev->ifc->disable(sdev);		sdev->enabled = 0;	}} static voidsddump(void){	SDev *sdev; 	print("sdevs:\n");	for(sdev = sdlist; sdev != nil; sdev = sdev->next){		print("sdev %c index %d nunit %d: ",			sdev->idno, sdev->index, sdev->nunit);		print("\n");	}} static int_sdinit(void){	ulong m;	int i;	SDev *sdev, *tail;	SDunit *unit; 	/*	 * Probe all configured controllers and make a list	 * of devices found, accumulating a possible maximum number	 * of units attached and marking each device with an index	 * into the linear top-level directory array of units.	 */	tail = nil;	for(i = 0; sdifc[i] != nil; i++){		if((sdev = sdifc[i]->pnp()) == nil)			continue;		if(sdlist != nil)			tail->next = sdev;		else			sdlist = sdev;		for(tail = sdev; tail->next != nil; tail = tail->next){			tail->index = sdnunit;			sdnunit += tail->nunit;		}		tail->index = sdnunit;		sdnunit += tail->nunit;	}	/*	 * Legacy and option code goes here. This will be hard...	 */ 	/*	 * The maximum number of possible units is known, allocate	 * placeholders for their datastructures; the units will be	 * probed and structures allocated when attached.	 * Allocate controller names for the different types.	 */	if(sdnunit == 0)		return 0;	if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil)		return 0;	sddetach = _sddetach; 	for(i = 0; sdifc[i] != nil; i++){		if(sdifc[i]->id)			sdifc[i]->id(sdlist);	}	if (0)		sddump(); 	m = 0;	cdmask = sdmask = 0;	for(i=0; i<sdnunit && i < 32; i++) {		unit = sdindex2unit(i);		if(unit == nil)			continue;		sdinitpart(unit);		partition(unit);		if(unit->npart > 0){	/* BUG */			if((unit->inquiry[0] & 0x1F) == 0x05)				cdmask |= (1<<i);			else				sdmask |= (1<<i);			m |= (1<<i);		}	} //notesdinfo();	_sdmask = m;	return m;} intcdinit(void){	if(sdnunit == 0)		_sdinit();	return cdmask;} intsdinit(void){	if(sdnunit == 0)		_sdinit();	return sdmask;} voidsdinitdev(int i, char *s){	SDunit *unit; 	unit = sdindex2unit(i);	strcpy(s, unit->name);} voidsdprintdevs(int i){	char *s;	SDunit *unit; 	unit = sdindex2unit(i);	for(i=0; i<unit->npart; i++){		s = unit->part[i].name;		if(strncmp(s, "dos", 3) == 0		|| strncmp(s, "9fat", 4) == 0		|| strncmp(s, "fs", 2) == 0)			print(" %s!%s", unit->name, s);	}} SDpart*sdfindpart(SDunit *unit, char *name){	int i; 	if(parttrace)		print("findpart %d %s %s\t\n", unit->npart, unit->name, name);	for(i=0; i<unit->npart; i++) {		if(parttrace)			print("%s...", unit->part[i].name);		if(strcmp(unit->part[i].name, name) == 0){			if(parttrace)				print("\n");			return &unit->part[i];		}	}	if(parttrace)		print("not found\n");	return nil;} typedef struct Scsicrud Scsicrud;struct Scsicrud {	Fs fs;	vlong offset;	SDunit *unit;	SDpart *part;}; longsdread(Fs *vcrud, void *v, long n){	Scsicrud *crud;	long x; 	crud = (Scsicrud*)vcrud;	x = sdbio(crud->unit, crud->part, v, n, crud->offset);	if(x > 0)		crud->offset += x;	return x;} vlongsdseek(Fs *vcrud, vlong seek){	((Scsicrud*)vcrud)->offset = seek;	return seek;} void*sdgetfspart(int i, char *s, int chatty){	SDunit *unit;	SDpart *p;	Scsicrud *crud; 	if(cdmask&(1<<i)){		if(strcmp(s, "cdboot") != 0)			return nil;	}else if(sdmask&(1<<i)){		if(strcmp(s, "cdboot") == 0)			return nil;	} 	unit = sdindex2unit(i);	if((p = sdfindpart(unit, s)) == nil){		if(chatty)			print("unknown partition %s!%s\n", unit->name, s);		return nil;	}	if(p->crud == nil) {		crud = malloc(sizeof(Scsicrud));		crud->fs.dev = i;		crud->fs.diskread = sdread;		crud->fs.diskseek = sdseek;	//	crud->start = 0;		crud->unit = unit;		crud->part = p;		if(dosinit(&crud->fs) < 0 && dosinit(&crud->fs) < 0 && kfsinit(&crud->fs) < 0){			if(chatty)				print("partition %s!%s does not contain a DOS or KFS file system\n",					unit->name, s);			return nil;		}		p->crud = crud;	}	return p->crud;} /* * Leave partitions around for devsd to pick up. * (Needed by boot process; more extensive  * partitioning is done by termrc or cpurc). */voidsdaddconf(int i){	SDunit *unit;	SDpart *pp; 	unit = sdindex2unit(i);		/*	 * If there were no partitions (just data and partition), don't bother.	 */	if(unit->npart<= 1 || (unit->npart==2 && strcmp(unit->part[1].name, "partition")==0))		return; 	addconf("%spart=", unit->name);	for(i=1, pp=&unit->part[i]; i<unit->npart; i++, pp++)	/* skip 0, which is "data" */		addconf("%s%s %lld %lld", i==1 ? "" : "/", pp->name,			pp->start, pp->end);	addconf("\n");} intsdboot(int dev, char *pname, Boot *b){	char *file;	Fs *fs; 	if((file = strchr(pname, '!')) == nil) {		print("syntax is sdC0!partition!file\n");		return -1;	}	*file++ = '\0'; 	fs = sdgetfspart(dev, pname, 1);	if(fs == nil)		return -1; 	return fsboot(fs, file, b);} longsdbio(SDunit *unit, SDpart *pp, void* va, long len, vlong off){	long l;	ulong bno, max, nb, offset;	static uchar *b;	char *a;	static ulong bsz; 	a = va;memset(a, 0xDA, len);	qlock(&unit->ctl);

Lines 1–500 of 631.