717 lines · 14.2 KB · C
RawDownload
/* * Storage Device. */#include "all.h"#include "io.h"#include "mem.h" #include "sd.h"#undef error #define parttrace(...) //print(__VA_ARGS__)#define partaddtrace(...) //print(__VA_ARGS__) extern SDifc sdataifc; SDifc* sdifc[] = {	&sdataifc,	nil,}; static SDev* sdlist;static SDunit** sdunit;static int sdnunit;static int _sdmask;static int cdmask;static int sdmask;static QLock sdqlock; // didn't want to confuse the diff.static int _sdinit(void); static char devletters[] = "0123456789"	"abcdefghijklmnopqrstuvwxyz"	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static SDev *devs[sizeof devletters-1]; static intsdnextid(SDev *dev, int id){	char *p;	int id0; 	p = strchr(devletters, id);	if(p == nil)		panic("bad driveletter %d\n", id);	id0 = id = p-devletters;	for(;;){		if(devs[id] == 0)			break;		id = id+1%nelem(devs);		if(id == id0)			panic("no drives available");	} //print("assigining %c; requested %c\n", devletters[id], devletters[id0]); 	devs[id] = dev;	return devletters[id];} voidsdaddpart(SDunit* unit, char* name, Devsize start, Devsize end){	SDpart *pp;	int i, partno; 	partaddtrace("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){					parttrace("already present\n");					return;				}			}		}	}else{		if((unit->part = ialloc(sizeof(SDpart)*SDnpart, 0)) == nil){			parttrace("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; 	parttrace("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 voidadd9loadparts(SDunit *unit){	char *s, *v[16], *w[3], buf[80];	int i, n;			snprint(buf, sizeof buf, "%spart", unit->name);	if((s = getconf(buf)) == 0)		return; 	strncpy(buf, s, sizeof buf-2);	buf[sizeof buf-1] = 0;	n = getfields(buf, v, nelem(v), 0, "/");	for(i = 0; i<n; i++){		if(getfields(v[i], w, nelem(w), 0, " ") != 3)			continue;		sdaddpart(unit, w[0], strtoull(w[1], 0, 0), strtoull(w[2], 0, 0));	}} static intsdinitpart(SDunit* unit){	unit->sectors = unit->secsize = 0;	unit->npart = 0;	if(unit->part){//		free(unit->part);		unit->part = nil;	} 	parttrace("sdinitpart\n");	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:		parttrace("unknown device type: %x\n", unit->inquiry[0] & 0x1F);		return 0;	} 	if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0){		parttrace("offline\n");		return 0;	}	parttrace("calling sdaddpart\n");	sdaddpart(unit, "data", 0, unit->sectors);	add9loadparts(unit);	return 1;} SDunit*sdgetunit(SDev* sdev, int subno){	int index;	SDunit *unit; 	parttrace("sdgetunit(%s, %d)\n", sdev->ifc->name, subno);	if(sdlist == nil)		_sdinit();	if(subno >= sdnunit){		parttrace("sdgetunit: partition out-of-range %d >= %d\n", subno, sdnunit);		return nil;	}	/*	 * 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 = ialloc(sizeof(SDunit), 0)) == 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);			parttrace("sdgetunit() -> nil\n");			return nil;		}		sdunit[index] = unit;	}	qunlock(&sdqlock);	parttrace("sdgetunit() -> %s\n", unit->name);	return unit;} 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 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.	 */	parttrace("_sdinit()\n");	tail = nil;	for(i = 0; sdifc[i] != nil; i++){		parttrace("probe %s\n", sdifc[i]->name);		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->idno = sdnextid(tail, tail->idno);			parttrace("\t" "[%2d.%2d]", sdnunit, sdnunit+tail->nunit-1);			tail->index = sdnunit;			sdnunit += tail->nunit;		}		tail->idno = sdnextid(tail, tail->idno);		parttrace("\t" "[%2d.%2d]\n", sdnunit, sdnunit+tail->nunit-1);		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 = ialloc(sdnunit*sizeof(SDunit*), 0)) == nil)		return 0;//	sddetach = _sddetach; 	for(i = 0; sdifc[i] != nil; i++){		if(sdifc[i]->id)			sdifc[i]->id(sdlist);	} 	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;} //int//cdinit(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);} //void//sdprintdevs(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; 	parttrace("findpart %d %s %s\t\n", unit->npart, unit->name, name);	for(i=0; i<unit->npart; i++) {		parttrace("%s...", unit->part[i].name);		if(strcmp(unit->part[i].name, name) == 0){			parttrace("\n");			return &unit->part[i];		}	}	parttrace("not found\n");	return nil;} longsdbio(SDunit *unit, SDpart *pp, void* va, long len, Off off){	Off l;	Off bno, max, nb, offset;	char *a;	static uchar *b;	static ulong bsz; 	a = va;	qlock(&unit->ctl);	if(unit->changed){		qunlock(&unit->ctl);		return 0;	} 	/*	 * Check the request is within bounds.	 * Removeable drives are locked throughout the I/O	 * in case the media changes unexpectedly.	 * Non-removeable drives are not locked during the I/O	 * to allow the hardware to optimise if it can; this is	 * a little fast and loose.	 * It's assumed that non-removable media parameters	 * (sectors, secsize) can't change once the drive has	 * been brought online.	 */	bno = (off/unit->secsize) + pp->start;	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;	max = SDmaxio/unit->secsize;	if(nb > max)		nb = max;	if(bno+nb > pp->end)		nb = pp->end - bno;	if(bno >= pp->end || nb == 0){		qunlock(&unit->ctl);		return 0;	}	if(!(unit->inquiry[1] & 0x80))		qunlock(&unit->ctl); 	if(bsz < nb*unit->secsize){		b = ialloc(nb*unit->secsize, 0);		bsz = nb*unit->secsize;	}//	b = sdmalloc(nb*unit->secsize);//	if(b == nil)//		return 0; 	offset = off%unit->secsize;	l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);	if(l < 0) {//		sdfree(b);		return 0;	} 	if(l < offset)		len = 0;	else if(len > l - offset)		len = l - offset;	if(len)		memmove(a, b+offset, len);//	sdfree(b); 	if(unit->inquiry[1] & 0x80)		qunlock(&unit->ctl); 	return len;} #ifdef DMAlongsdrio(SDreq *r, void* a, long n){	if(n >= SDmaxio || n < 0)		return 0; 	r->data = nil;	if(n){		if((r->data = malloc(n)) == nil)			return 0;		if(r->write)			memmove(r->data, a, n);	}	r->dlen = n; 	if(r->unit->dev->ifc->rio(r) != SDok){// cgascreenputs("1", 1);		if(r->data != nil){			sdfree(r->data);			r->data = nil;		}		return 0;

Lines 1–500 of 717.