xref: /inferno-os/os/boot/pc/devsd.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth  * Storage Device.
374a4d8c2SCharles.Forsyth  */
474a4d8c2SCharles.Forsyth #include "u.h"
574a4d8c2SCharles.Forsyth #include "mem.h"
674a4d8c2SCharles.Forsyth #include "lib.h"
774a4d8c2SCharles.Forsyth #include "dat.h"
874a4d8c2SCharles.Forsyth #include "fns.h"
974a4d8c2SCharles.Forsyth #include "io.h"
1074a4d8c2SCharles.Forsyth #include "ureg.h"
1174a4d8c2SCharles.Forsyth #include "error.h"
1274a4d8c2SCharles.Forsyth 
1374a4d8c2SCharles.Forsyth #include "sd.h"
1474a4d8c2SCharles.Forsyth #include "fs.h"
1574a4d8c2SCharles.Forsyth 
1674a4d8c2SCharles.Forsyth #define parttrace 0
1774a4d8c2SCharles.Forsyth 
1874a4d8c2SCharles.Forsyth 
1974a4d8c2SCharles.Forsyth extern SDifc* sdifc[];
2074a4d8c2SCharles.Forsyth 
2174a4d8c2SCharles.Forsyth static SDev* sdlist;
2274a4d8c2SCharles.Forsyth static SDunit** sdunit;
2374a4d8c2SCharles.Forsyth static int sdnunit;
2474a4d8c2SCharles.Forsyth static int _sdmask;
2574a4d8c2SCharles.Forsyth static int cdmask;
2674a4d8c2SCharles.Forsyth static int sdmask;
2774a4d8c2SCharles.Forsyth 
2874a4d8c2SCharles.Forsyth enum {
2974a4d8c2SCharles.Forsyth 	Rawcmd,
3074a4d8c2SCharles.Forsyth 	Rawdata,
3174a4d8c2SCharles.Forsyth 	Rawstatus,
3274a4d8c2SCharles.Forsyth };
3374a4d8c2SCharles.Forsyth 
3474a4d8c2SCharles.Forsyth void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)35*8a8c2d74SCharles.Forsyth sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
3674a4d8c2SCharles.Forsyth {
3774a4d8c2SCharles.Forsyth 	SDpart *pp;
3874a4d8c2SCharles.Forsyth 	int i, partno;
3974a4d8c2SCharles.Forsyth 
4074a4d8c2SCharles.Forsyth 	if(parttrace)
41*8a8c2d74SCharles.Forsyth 		print("add %d %s %s %lld %lld\n", unit->npart, unit->name, name, start, end);
4274a4d8c2SCharles.Forsyth 	/*
4374a4d8c2SCharles.Forsyth 	 * Check name not already used
4474a4d8c2SCharles.Forsyth 	 * and look for a free slot.
4574a4d8c2SCharles.Forsyth 	 */
4674a4d8c2SCharles.Forsyth 	if(unit->part != nil){
4774a4d8c2SCharles.Forsyth 		partno = -1;
4874a4d8c2SCharles.Forsyth 		for(i = 0; i < SDnpart; i++){
4974a4d8c2SCharles.Forsyth 			pp = &unit->part[i];
5074a4d8c2SCharles.Forsyth 			if(!pp->valid){
5174a4d8c2SCharles.Forsyth 				if(partno == -1)
5274a4d8c2SCharles.Forsyth 					partno = i;
5374a4d8c2SCharles.Forsyth 				break;
5474a4d8c2SCharles.Forsyth 			}
5574a4d8c2SCharles.Forsyth 			if(strcmp(name, pp->name) == 0){
5674a4d8c2SCharles.Forsyth 				if(pp->start == start && pp->end == end){
5774a4d8c2SCharles.Forsyth 					if(parttrace)
5874a4d8c2SCharles.Forsyth 						print("already present\n");
5974a4d8c2SCharles.Forsyth 					return;
6074a4d8c2SCharles.Forsyth 				}
6174a4d8c2SCharles.Forsyth 			}
6274a4d8c2SCharles.Forsyth 		}
6374a4d8c2SCharles.Forsyth 	}else{
6474a4d8c2SCharles.Forsyth 		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil){
6574a4d8c2SCharles.Forsyth 			if(parttrace)
6674a4d8c2SCharles.Forsyth 				print("malloc failed\n");
6774a4d8c2SCharles.Forsyth 			return;
6874a4d8c2SCharles.Forsyth 		}
6974a4d8c2SCharles.Forsyth 		partno = 0;
7074a4d8c2SCharles.Forsyth 	}
7174a4d8c2SCharles.Forsyth 
7274a4d8c2SCharles.Forsyth 	/*
7374a4d8c2SCharles.Forsyth 	 * Check there is a free slot and size and extent are valid.
7474a4d8c2SCharles.Forsyth 	 */
7574a4d8c2SCharles.Forsyth 	if(partno == -1 || start > end || end > unit->sectors){
76*8a8c2d74SCharles.Forsyth 		print("cannot add %s!%s [%llud,%llud) to disk [0,%llud): %s\n",
7774a4d8c2SCharles.Forsyth 			unit->name, name, start, end, unit->sectors,
7874a4d8c2SCharles.Forsyth 			partno==-1 ? "no free partitions" : "partition boundaries out of range");
7974a4d8c2SCharles.Forsyth 		return;
8074a4d8c2SCharles.Forsyth 	}
8174a4d8c2SCharles.Forsyth 	pp = &unit->part[partno];
8274a4d8c2SCharles.Forsyth 	pp->start = start;
8374a4d8c2SCharles.Forsyth 	pp->end = end;
8474a4d8c2SCharles.Forsyth 	strncpy(pp->name, name, NAMELEN);
8574a4d8c2SCharles.Forsyth 	pp->valid = 1;
8674a4d8c2SCharles.Forsyth 	unit->npart++;
8774a4d8c2SCharles.Forsyth }
8874a4d8c2SCharles.Forsyth 
8974a4d8c2SCharles.Forsyth void
sddelpart(SDunit * unit,char * name)9074a4d8c2SCharles.Forsyth sddelpart(SDunit* unit,  char* name)
9174a4d8c2SCharles.Forsyth {
9274a4d8c2SCharles.Forsyth 	int i;
9374a4d8c2SCharles.Forsyth 	SDpart *pp;
9474a4d8c2SCharles.Forsyth 
9574a4d8c2SCharles.Forsyth 	if(parttrace)
9674a4d8c2SCharles.Forsyth 		print("del %d %s %s\n", unit->npart, unit->name, name);
9774a4d8c2SCharles.Forsyth 	/*
9874a4d8c2SCharles.Forsyth 	 * Look for the partition to delete.
9974a4d8c2SCharles.Forsyth 	 * Can't delete if someone still has it open.
10074a4d8c2SCharles.Forsyth 	 * If it's the last valid partition zap the
10174a4d8c2SCharles.Forsyth 	 * whole table.
10274a4d8c2SCharles.Forsyth 	 */
10374a4d8c2SCharles.Forsyth 	pp = unit->part;
10474a4d8c2SCharles.Forsyth 	for(i = 0; i < SDnpart; i++){
10574a4d8c2SCharles.Forsyth 		if(strncmp(name, pp->name, NAMELEN) == 0)
10674a4d8c2SCharles.Forsyth 			break;
10774a4d8c2SCharles.Forsyth 		pp++;
10874a4d8c2SCharles.Forsyth 	}
10974a4d8c2SCharles.Forsyth 	if(i >= SDnpart)
11074a4d8c2SCharles.Forsyth 		return;
11174a4d8c2SCharles.Forsyth 	pp->valid = 0;
11274a4d8c2SCharles.Forsyth 
11374a4d8c2SCharles.Forsyth 	unit->npart--;
11474a4d8c2SCharles.Forsyth 	if(unit->npart == 0){
11574a4d8c2SCharles.Forsyth 		free(unit->part);
11674a4d8c2SCharles.Forsyth 		unit->part = nil;
11774a4d8c2SCharles.Forsyth 	}
11874a4d8c2SCharles.Forsyth }
11974a4d8c2SCharles.Forsyth 
12074a4d8c2SCharles.Forsyth static int
sdinitpart(SDunit * unit)12174a4d8c2SCharles.Forsyth sdinitpart(SDunit* unit)
12274a4d8c2SCharles.Forsyth {
12374a4d8c2SCharles.Forsyth 	unit->sectors = unit->secsize = 0;
12474a4d8c2SCharles.Forsyth 	unit->npart = 0;
12574a4d8c2SCharles.Forsyth 	if(unit->part){
12674a4d8c2SCharles.Forsyth 		free(unit->part);
12774a4d8c2SCharles.Forsyth 		unit->part = nil;
12874a4d8c2SCharles.Forsyth 	}
12974a4d8c2SCharles.Forsyth 
13074a4d8c2SCharles.Forsyth 	if(unit->inquiry[0] & 0xC0)
13174a4d8c2SCharles.Forsyth 		return 0;
13274a4d8c2SCharles.Forsyth 	switch(unit->inquiry[0] & 0x1F){
13374a4d8c2SCharles.Forsyth 	case 0x00:			/* DA */
13474a4d8c2SCharles.Forsyth 	case 0x04:			/* WORM */
13574a4d8c2SCharles.Forsyth 	case 0x05:			/* CD-ROM */
13674a4d8c2SCharles.Forsyth 	case 0x07:			/* MO */
13774a4d8c2SCharles.Forsyth 		break;
13874a4d8c2SCharles.Forsyth 	default:
13974a4d8c2SCharles.Forsyth 		return 0;
14074a4d8c2SCharles.Forsyth 	}
14174a4d8c2SCharles.Forsyth 
14274a4d8c2SCharles.Forsyth 	if(unit->dev->ifc->online == nil || unit->dev->ifc->online(unit) == 0)
14374a4d8c2SCharles.Forsyth 		return 0;
14474a4d8c2SCharles.Forsyth 	sdaddpart(unit, "data", 0, unit->sectors);
14574a4d8c2SCharles.Forsyth 	return 1;
14674a4d8c2SCharles.Forsyth }
14774a4d8c2SCharles.Forsyth 
14874a4d8c2SCharles.Forsyth static SDunit*
sdgetunit(SDev * sdev,int subno)14974a4d8c2SCharles.Forsyth sdgetunit(SDev* sdev, int subno)
15074a4d8c2SCharles.Forsyth {
15174a4d8c2SCharles.Forsyth 	int index;
15274a4d8c2SCharles.Forsyth 	SDunit *unit;
15374a4d8c2SCharles.Forsyth 
15474a4d8c2SCharles.Forsyth 	/*
15574a4d8c2SCharles.Forsyth 	 * Associate a unit with a given device and sub-unit
15674a4d8c2SCharles.Forsyth 	 * number on that device.
15774a4d8c2SCharles.Forsyth 	 * The device will be probed if it has not already been
15874a4d8c2SCharles.Forsyth 	 * successfully accessed.
15974a4d8c2SCharles.Forsyth 	 */
16074a4d8c2SCharles.Forsyth 	qlock(&sdqlock);
16174a4d8c2SCharles.Forsyth 	index = sdev->index+subno;
16274a4d8c2SCharles.Forsyth 	unit = sdunit[index];
16374a4d8c2SCharles.Forsyth 	if(unit == nil){
16474a4d8c2SCharles.Forsyth 		if((unit = malloc(sizeof(SDunit))) == nil){
16574a4d8c2SCharles.Forsyth 			qunlock(&sdqlock);
16674a4d8c2SCharles.Forsyth 			return nil;
16774a4d8c2SCharles.Forsyth 		}
16874a4d8c2SCharles.Forsyth 
16974a4d8c2SCharles.Forsyth 		if(sdev->enabled == 0 && sdev->ifc->enable)
17074a4d8c2SCharles.Forsyth 			sdev->ifc->enable(sdev);
17174a4d8c2SCharles.Forsyth 		sdev->enabled = 1;
17274a4d8c2SCharles.Forsyth 
17374a4d8c2SCharles.Forsyth 		snprint(unit->name, NAMELEN, "sd%c%d", sdev->idno, subno);
17474a4d8c2SCharles.Forsyth 		unit->subno = subno;
17574a4d8c2SCharles.Forsyth 		unit->dev = sdev;
17674a4d8c2SCharles.Forsyth 
17774a4d8c2SCharles.Forsyth 		/*
17874a4d8c2SCharles.Forsyth 		 * No need to lock anything here as this is only
17974a4d8c2SCharles.Forsyth 		 * called before the unit is made available in the
18074a4d8c2SCharles.Forsyth 		 * sdunit[] array.
18174a4d8c2SCharles.Forsyth 		 */
18274a4d8c2SCharles.Forsyth 		if(unit->dev->ifc->verify(unit) == 0){
18374a4d8c2SCharles.Forsyth 			qunlock(&sdqlock);
18474a4d8c2SCharles.Forsyth 			free(unit);
18574a4d8c2SCharles.Forsyth 			return nil;
18674a4d8c2SCharles.Forsyth 		}
18774a4d8c2SCharles.Forsyth 		sdunit[index] = unit;
18874a4d8c2SCharles.Forsyth 	}
18974a4d8c2SCharles.Forsyth 	qunlock(&sdqlock);
19074a4d8c2SCharles.Forsyth 
19174a4d8c2SCharles.Forsyth 	return unit;
19274a4d8c2SCharles.Forsyth }
19374a4d8c2SCharles.Forsyth 
19474a4d8c2SCharles.Forsyth static SDunit*
sdindex2unit(int index)19574a4d8c2SCharles.Forsyth sdindex2unit(int index)
19674a4d8c2SCharles.Forsyth {
19774a4d8c2SCharles.Forsyth 	SDev *sdev;
19874a4d8c2SCharles.Forsyth 
19974a4d8c2SCharles.Forsyth 	/*
20074a4d8c2SCharles.Forsyth 	 * Associate a unit with a given index into the top-level
20174a4d8c2SCharles.Forsyth 	 * device directory.
20274a4d8c2SCharles.Forsyth 	 * The device will be probed if it has not already been
20374a4d8c2SCharles.Forsyth 	 * successfully accessed.
20474a4d8c2SCharles.Forsyth 	 */
20574a4d8c2SCharles.Forsyth 	for(sdev = sdlist; sdev != nil; sdev = sdev->next){
20674a4d8c2SCharles.Forsyth 		if(index >= sdev->index && index < sdev->index+sdev->nunit)
20774a4d8c2SCharles.Forsyth 			return sdgetunit(sdev, index-sdev->index);
20874a4d8c2SCharles.Forsyth 	}
20974a4d8c2SCharles.Forsyth 
21074a4d8c2SCharles.Forsyth 	return nil;
21174a4d8c2SCharles.Forsyth }
21274a4d8c2SCharles.Forsyth 
21374a4d8c2SCharles.Forsyth static void
_sddetach(void)21474a4d8c2SCharles.Forsyth _sddetach(void)
21574a4d8c2SCharles.Forsyth {
21674a4d8c2SCharles.Forsyth 	SDev *sdev;
21774a4d8c2SCharles.Forsyth 
21874a4d8c2SCharles.Forsyth 	for(sdev = sdlist; sdev != nil; sdev = sdev->next){
21974a4d8c2SCharles.Forsyth 		if(sdev->enabled == 0)
22074a4d8c2SCharles.Forsyth 			continue;
22174a4d8c2SCharles.Forsyth 		if(sdev->ifc->disable)
22274a4d8c2SCharles.Forsyth 			sdev->ifc->disable(sdev);
22374a4d8c2SCharles.Forsyth 		sdev->enabled = 0;
22474a4d8c2SCharles.Forsyth 	}
22574a4d8c2SCharles.Forsyth }
22674a4d8c2SCharles.Forsyth 
227*8a8c2d74SCharles.Forsyth static void
sddump(void)228*8a8c2d74SCharles.Forsyth sddump(void)
229*8a8c2d74SCharles.Forsyth {
230*8a8c2d74SCharles.Forsyth 	SDev *sdev;
231*8a8c2d74SCharles.Forsyth 
232*8a8c2d74SCharles.Forsyth 	print("sdevs:\n");
233*8a8c2d74SCharles.Forsyth 	for(sdev = sdlist; sdev != nil; sdev = sdev->next){
234*8a8c2d74SCharles.Forsyth 		print("sdev %c index %d nunit %d: ",
235*8a8c2d74SCharles.Forsyth 			sdev->idno, sdev->index, sdev->nunit);
236*8a8c2d74SCharles.Forsyth 		print("\n");
237*8a8c2d74SCharles.Forsyth 	}
238*8a8c2d74SCharles.Forsyth }
239*8a8c2d74SCharles.Forsyth 
24074a4d8c2SCharles.Forsyth static int
_sdinit(void)24174a4d8c2SCharles.Forsyth _sdinit(void)
24274a4d8c2SCharles.Forsyth {
24374a4d8c2SCharles.Forsyth 	ulong m;
24474a4d8c2SCharles.Forsyth 	int i;
24574a4d8c2SCharles.Forsyth 	SDev *sdev, *tail;
24674a4d8c2SCharles.Forsyth 	SDunit *unit;
24774a4d8c2SCharles.Forsyth 
24874a4d8c2SCharles.Forsyth 	/*
24974a4d8c2SCharles.Forsyth 	 * Probe all configured controllers and make a list
25074a4d8c2SCharles.Forsyth 	 * of devices found, accumulating a possible maximum number
25174a4d8c2SCharles.Forsyth 	 * of units attached and marking each device with an index
25274a4d8c2SCharles.Forsyth 	 * into the linear top-level directory array of units.
25374a4d8c2SCharles.Forsyth 	 */
25474a4d8c2SCharles.Forsyth 	tail = nil;
25574a4d8c2SCharles.Forsyth 	for(i = 0; sdifc[i] != nil; i++){
25674a4d8c2SCharles.Forsyth 		if((sdev = sdifc[i]->pnp()) == nil)
25774a4d8c2SCharles.Forsyth 			continue;
25874a4d8c2SCharles.Forsyth 		if(sdlist != nil)
25974a4d8c2SCharles.Forsyth 			tail->next = sdev;
26074a4d8c2SCharles.Forsyth 		else
26174a4d8c2SCharles.Forsyth 			sdlist = sdev;
26274a4d8c2SCharles.Forsyth 		for(tail = sdev; tail->next != nil; tail = tail->next){
263*8a8c2d74SCharles.Forsyth 			tail->index = sdnunit;
26474a4d8c2SCharles.Forsyth 			sdnunit += tail->nunit;
26574a4d8c2SCharles.Forsyth 		}
26674a4d8c2SCharles.Forsyth 		tail->index = sdnunit;
26774a4d8c2SCharles.Forsyth 		sdnunit += tail->nunit;
26874a4d8c2SCharles.Forsyth 	}
26974a4d8c2SCharles.Forsyth 	/*
27074a4d8c2SCharles.Forsyth 	 * Legacy and option code goes here. This will be hard...
27174a4d8c2SCharles.Forsyth 	 */
27274a4d8c2SCharles.Forsyth 
27374a4d8c2SCharles.Forsyth 	/*
27474a4d8c2SCharles.Forsyth 	 * The maximum number of possible units is known, allocate
27574a4d8c2SCharles.Forsyth 	 * placeholders for their datastructures; the units will be
27674a4d8c2SCharles.Forsyth 	 * probed and structures allocated when attached.
27774a4d8c2SCharles.Forsyth 	 * Allocate controller names for the different types.
27874a4d8c2SCharles.Forsyth 	 */
27974a4d8c2SCharles.Forsyth 	if(sdnunit == 0)
28074a4d8c2SCharles.Forsyth 		return 0;
28174a4d8c2SCharles.Forsyth 	if((sdunit = malloc(sdnunit*sizeof(SDunit*))) == nil)
28274a4d8c2SCharles.Forsyth 		return 0;
28374a4d8c2SCharles.Forsyth 	sddetach = _sddetach;
28474a4d8c2SCharles.Forsyth 
28574a4d8c2SCharles.Forsyth 	for(i = 0; sdifc[i] != nil; i++){
28674a4d8c2SCharles.Forsyth 		if(sdifc[i]->id)
28774a4d8c2SCharles.Forsyth 			sdifc[i]->id(sdlist);
28874a4d8c2SCharles.Forsyth 	}
289*8a8c2d74SCharles.Forsyth 	if (0)
290*8a8c2d74SCharles.Forsyth 		sddump();
29174a4d8c2SCharles.Forsyth 
29274a4d8c2SCharles.Forsyth 	m = 0;
29374a4d8c2SCharles.Forsyth 	cdmask = sdmask = 0;
29474a4d8c2SCharles.Forsyth 	for(i=0; i<sdnunit && i < 32; i++) {
29574a4d8c2SCharles.Forsyth 		unit = sdindex2unit(i);
29674a4d8c2SCharles.Forsyth 		if(unit == nil)
29774a4d8c2SCharles.Forsyth 			continue;
29874a4d8c2SCharles.Forsyth 		sdinitpart(unit);
29974a4d8c2SCharles.Forsyth 		partition(unit);
30074a4d8c2SCharles.Forsyth 		if(unit->npart > 0){	/* BUG */
30174a4d8c2SCharles.Forsyth 			if((unit->inquiry[0] & 0x1F) == 0x05)
30274a4d8c2SCharles.Forsyth 				cdmask |= (1<<i);
30374a4d8c2SCharles.Forsyth 			else
30474a4d8c2SCharles.Forsyth 				sdmask |= (1<<i);
30574a4d8c2SCharles.Forsyth 			m |= (1<<i);
30674a4d8c2SCharles.Forsyth 		}
30774a4d8c2SCharles.Forsyth 	}
30874a4d8c2SCharles.Forsyth 
30974a4d8c2SCharles.Forsyth //notesdinfo();
31074a4d8c2SCharles.Forsyth 	_sdmask = m;
31174a4d8c2SCharles.Forsyth 	return m;
31274a4d8c2SCharles.Forsyth }
31374a4d8c2SCharles.Forsyth 
31474a4d8c2SCharles.Forsyth int
cdinit(void)31574a4d8c2SCharles.Forsyth cdinit(void)
31674a4d8c2SCharles.Forsyth {
31774a4d8c2SCharles.Forsyth 	if(sdnunit == 0)
31874a4d8c2SCharles.Forsyth 		_sdinit();
31974a4d8c2SCharles.Forsyth 	return cdmask;
32074a4d8c2SCharles.Forsyth }
32174a4d8c2SCharles.Forsyth 
32274a4d8c2SCharles.Forsyth int
sdinit(void)32374a4d8c2SCharles.Forsyth sdinit(void)
32474a4d8c2SCharles.Forsyth {
32574a4d8c2SCharles.Forsyth 	if(sdnunit == 0)
32674a4d8c2SCharles.Forsyth 		_sdinit();
32774a4d8c2SCharles.Forsyth 	return sdmask;
32874a4d8c2SCharles.Forsyth }
32974a4d8c2SCharles.Forsyth 
33074a4d8c2SCharles.Forsyth void
sdinitdev(int i,char * s)33174a4d8c2SCharles.Forsyth sdinitdev(int i, char *s)
33274a4d8c2SCharles.Forsyth {
33374a4d8c2SCharles.Forsyth 	SDunit *unit;
33474a4d8c2SCharles.Forsyth 
33574a4d8c2SCharles.Forsyth 	unit = sdindex2unit(i);
33674a4d8c2SCharles.Forsyth 	strcpy(s, unit->name);
33774a4d8c2SCharles.Forsyth }
33874a4d8c2SCharles.Forsyth 
33974a4d8c2SCharles.Forsyth void
sdprintdevs(int i)34074a4d8c2SCharles.Forsyth sdprintdevs(int i)
34174a4d8c2SCharles.Forsyth {
34274a4d8c2SCharles.Forsyth 	char *s;
34374a4d8c2SCharles.Forsyth 	SDunit *unit;
34474a4d8c2SCharles.Forsyth 
34574a4d8c2SCharles.Forsyth 	unit = sdindex2unit(i);
34674a4d8c2SCharles.Forsyth 	for(i=0; i<unit->npart; i++){
34774a4d8c2SCharles.Forsyth 		s = unit->part[i].name;
34874a4d8c2SCharles.Forsyth 		if(strncmp(s, "dos", 3) == 0
34974a4d8c2SCharles.Forsyth 		|| strncmp(s, "9fat", 4) == 0
35074a4d8c2SCharles.Forsyth 		|| strncmp(s, "fs", 2) == 0)
35174a4d8c2SCharles.Forsyth 			print(" %s!%s", unit->name, s);
35274a4d8c2SCharles.Forsyth 	}
35374a4d8c2SCharles.Forsyth }
35474a4d8c2SCharles.Forsyth 
35574a4d8c2SCharles.Forsyth SDpart*
sdfindpart(SDunit * unit,char * name)35674a4d8c2SCharles.Forsyth sdfindpart(SDunit *unit, char *name)
35774a4d8c2SCharles.Forsyth {
35874a4d8c2SCharles.Forsyth 	int i;
35974a4d8c2SCharles.Forsyth 
36074a4d8c2SCharles.Forsyth 	if(parttrace)
36174a4d8c2SCharles.Forsyth 		print("findpart %d %s %s\t\n", unit->npart, unit->name, name);
36274a4d8c2SCharles.Forsyth 	for(i=0; i<unit->npart; i++) {
36374a4d8c2SCharles.Forsyth 		if(parttrace)
36474a4d8c2SCharles.Forsyth 			print("%s...", unit->part[i].name);
36574a4d8c2SCharles.Forsyth 		if(strcmp(unit->part[i].name, name) == 0){
36674a4d8c2SCharles.Forsyth 			if(parttrace)
36774a4d8c2SCharles.Forsyth 				print("\n");
36874a4d8c2SCharles.Forsyth 			return &unit->part[i];
36974a4d8c2SCharles.Forsyth 		}
37074a4d8c2SCharles.Forsyth 	}
37174a4d8c2SCharles.Forsyth 	if(parttrace)
37274a4d8c2SCharles.Forsyth 		print("not found\n");
37374a4d8c2SCharles.Forsyth 	return nil;
37474a4d8c2SCharles.Forsyth }
37574a4d8c2SCharles.Forsyth 
37674a4d8c2SCharles.Forsyth typedef struct Scsicrud Scsicrud;
37774a4d8c2SCharles.Forsyth struct Scsicrud {
37874a4d8c2SCharles.Forsyth 	Fs fs;
37974a4d8c2SCharles.Forsyth 	vlong offset;
38074a4d8c2SCharles.Forsyth 	SDunit *unit;
38174a4d8c2SCharles.Forsyth 	SDpart *part;
38274a4d8c2SCharles.Forsyth };
38374a4d8c2SCharles.Forsyth 
38474a4d8c2SCharles.Forsyth long
sdread(Fs * vcrud,void * v,long n)38574a4d8c2SCharles.Forsyth sdread(Fs *vcrud, void *v, long n)
38674a4d8c2SCharles.Forsyth {
38774a4d8c2SCharles.Forsyth 	Scsicrud *crud;
38874a4d8c2SCharles.Forsyth 	long x;
38974a4d8c2SCharles.Forsyth 
39074a4d8c2SCharles.Forsyth 	crud = (Scsicrud*)vcrud;
39174a4d8c2SCharles.Forsyth 	x = sdbio(crud->unit, crud->part, v, n, crud->offset);
39274a4d8c2SCharles.Forsyth 	if(x > 0)
39374a4d8c2SCharles.Forsyth 		crud->offset += x;
39474a4d8c2SCharles.Forsyth 	return x;
39574a4d8c2SCharles.Forsyth }
39674a4d8c2SCharles.Forsyth 
39774a4d8c2SCharles.Forsyth vlong
sdseek(Fs * vcrud,vlong seek)39874a4d8c2SCharles.Forsyth sdseek(Fs *vcrud, vlong seek)
39974a4d8c2SCharles.Forsyth {
40074a4d8c2SCharles.Forsyth 	((Scsicrud*)vcrud)->offset = seek;
40174a4d8c2SCharles.Forsyth 	return seek;
40274a4d8c2SCharles.Forsyth }
40374a4d8c2SCharles.Forsyth 
40474a4d8c2SCharles.Forsyth void*
sdgetfspart(int i,char * s,int chatty)40574a4d8c2SCharles.Forsyth sdgetfspart(int i, char *s, int chatty)
40674a4d8c2SCharles.Forsyth {
40774a4d8c2SCharles.Forsyth 	SDunit *unit;
40874a4d8c2SCharles.Forsyth 	SDpart *p;
40974a4d8c2SCharles.Forsyth 	Scsicrud *crud;
41074a4d8c2SCharles.Forsyth 
41174a4d8c2SCharles.Forsyth 	if(cdmask&(1<<i)){
41274a4d8c2SCharles.Forsyth 		if(strcmp(s, "cdboot") != 0)
41374a4d8c2SCharles.Forsyth 			return nil;
41474a4d8c2SCharles.Forsyth 	}else if(sdmask&(1<<i)){
41574a4d8c2SCharles.Forsyth 		if(strcmp(s, "cdboot") == 0)
41674a4d8c2SCharles.Forsyth 			return nil;
41774a4d8c2SCharles.Forsyth 	}
41874a4d8c2SCharles.Forsyth 
41974a4d8c2SCharles.Forsyth 	unit = sdindex2unit(i);
42074a4d8c2SCharles.Forsyth 	if((p = sdfindpart(unit, s)) == nil){
42174a4d8c2SCharles.Forsyth 		if(chatty)
42274a4d8c2SCharles.Forsyth 			print("unknown partition %s!%s\n", unit->name, s);
42374a4d8c2SCharles.Forsyth 		return nil;
42474a4d8c2SCharles.Forsyth 	}
42574a4d8c2SCharles.Forsyth 	if(p->crud == nil) {
42674a4d8c2SCharles.Forsyth 		crud = malloc(sizeof(Scsicrud));
42774a4d8c2SCharles.Forsyth 		crud->fs.dev = i;
42874a4d8c2SCharles.Forsyth 		crud->fs.diskread = sdread;
42974a4d8c2SCharles.Forsyth 		crud->fs.diskseek = sdseek;
43074a4d8c2SCharles.Forsyth 	//	crud->start = 0;
43174a4d8c2SCharles.Forsyth 		crud->unit = unit;
43274a4d8c2SCharles.Forsyth 		crud->part = p;
43374a4d8c2SCharles.Forsyth 		if(dosinit(&crud->fs) < 0 && dosinit(&crud->fs) < 0 && kfsinit(&crud->fs) < 0){
43474a4d8c2SCharles.Forsyth 			if(chatty)
43574a4d8c2SCharles.Forsyth 				print("partition %s!%s does not contain a DOS or KFS file system\n",
43674a4d8c2SCharles.Forsyth 					unit->name, s);
43774a4d8c2SCharles.Forsyth 			return nil;
43874a4d8c2SCharles.Forsyth 		}
43974a4d8c2SCharles.Forsyth 		p->crud = crud;
44074a4d8c2SCharles.Forsyth 	}
44174a4d8c2SCharles.Forsyth 	return p->crud;
44274a4d8c2SCharles.Forsyth }
44374a4d8c2SCharles.Forsyth 
44474a4d8c2SCharles.Forsyth /*
44574a4d8c2SCharles.Forsyth  * Leave partitions around for devsd to pick up.
44674a4d8c2SCharles.Forsyth  * (Needed by boot process; more extensive
44774a4d8c2SCharles.Forsyth  * partitioning is done by termrc or cpurc).
44874a4d8c2SCharles.Forsyth  */
44974a4d8c2SCharles.Forsyth void
sdaddconf(int i)45074a4d8c2SCharles.Forsyth sdaddconf(int i)
45174a4d8c2SCharles.Forsyth {
45274a4d8c2SCharles.Forsyth 	SDunit *unit;
45374a4d8c2SCharles.Forsyth 	SDpart *pp;
45474a4d8c2SCharles.Forsyth 
45574a4d8c2SCharles.Forsyth 	unit = sdindex2unit(i);
45674a4d8c2SCharles.Forsyth 
45774a4d8c2SCharles.Forsyth 	/*
45874a4d8c2SCharles.Forsyth 	 * If there were no partitions (just data and partition), don't bother.
45974a4d8c2SCharles.Forsyth 	 */
46074a4d8c2SCharles.Forsyth 	if(unit->npart<= 1 || (unit->npart==2 && strcmp(unit->part[1].name, "partition")==0))
46174a4d8c2SCharles.Forsyth 		return;
46274a4d8c2SCharles.Forsyth 
46374a4d8c2SCharles.Forsyth 	addconf("%spart=", unit->name);
46474a4d8c2SCharles.Forsyth 	for(i=1, pp=&unit->part[i]; i<unit->npart; i++, pp++)	/* skip 0, which is "data" */
465*8a8c2d74SCharles.Forsyth 		addconf("%s%s %lld %lld", i==1 ? "" : "/", pp->name,
46674a4d8c2SCharles.Forsyth 			pp->start, pp->end);
46774a4d8c2SCharles.Forsyth 	addconf("\n");
46874a4d8c2SCharles.Forsyth }
46974a4d8c2SCharles.Forsyth 
47074a4d8c2SCharles.Forsyth int
sdboot(int dev,char * pname,Boot * b)47174a4d8c2SCharles.Forsyth sdboot(int dev, char *pname, Boot *b)
47274a4d8c2SCharles.Forsyth {
47374a4d8c2SCharles.Forsyth 	char *file;
47474a4d8c2SCharles.Forsyth 	Fs *fs;
47574a4d8c2SCharles.Forsyth 
47674a4d8c2SCharles.Forsyth 	if((file = strchr(pname, '!')) == nil) {
47774a4d8c2SCharles.Forsyth 		print("syntax is sdC0!partition!file\n");
47874a4d8c2SCharles.Forsyth 		return -1;
47974a4d8c2SCharles.Forsyth 	}
48074a4d8c2SCharles.Forsyth 	*file++ = '\0';
48174a4d8c2SCharles.Forsyth 
48274a4d8c2SCharles.Forsyth 	fs = sdgetfspart(dev, pname, 1);
48374a4d8c2SCharles.Forsyth 	if(fs == nil)
48474a4d8c2SCharles.Forsyth 		return -1;
48574a4d8c2SCharles.Forsyth 
48674a4d8c2SCharles.Forsyth 	return fsboot(fs, file, b);
48774a4d8c2SCharles.Forsyth }
48874a4d8c2SCharles.Forsyth 
48974a4d8c2SCharles.Forsyth long
sdbio(SDunit * unit,SDpart * pp,void * va,long len,vlong off)49074a4d8c2SCharles.Forsyth sdbio(SDunit *unit, SDpart *pp, void* va, long len, vlong off)
49174a4d8c2SCharles.Forsyth {
49274a4d8c2SCharles.Forsyth 	long l;
49374a4d8c2SCharles.Forsyth 	ulong bno, max, nb, offset;
49474a4d8c2SCharles.Forsyth 	static uchar *b;
49574a4d8c2SCharles.Forsyth 	char *a;
49674a4d8c2SCharles.Forsyth 	static ulong bsz;
49774a4d8c2SCharles.Forsyth 
49874a4d8c2SCharles.Forsyth 	a = va;
49974a4d8c2SCharles.Forsyth memset(a, 0xDA, len);
50074a4d8c2SCharles.Forsyth 	qlock(&unit->ctl);
50174a4d8c2SCharles.Forsyth 	if(unit->changed){
50274a4d8c2SCharles.Forsyth 		qunlock(&unit->ctl);
50374a4d8c2SCharles.Forsyth 		return 0;
50474a4d8c2SCharles.Forsyth 	}
50574a4d8c2SCharles.Forsyth 
50674a4d8c2SCharles.Forsyth 	/*
50774a4d8c2SCharles.Forsyth 	 * Check the request is within bounds.
50874a4d8c2SCharles.Forsyth 	 * Removeable drives are locked throughout the I/O
50974a4d8c2SCharles.Forsyth 	 * in case the media changes unexpectedly.
51074a4d8c2SCharles.Forsyth 	 * Non-removeable drives are not locked during the I/O
51174a4d8c2SCharles.Forsyth 	 * to allow the hardware to optimise if it can; this is
51274a4d8c2SCharles.Forsyth 	 * a little fast and loose.
51374a4d8c2SCharles.Forsyth 	 * It's assumed that non-removable media parameters
51474a4d8c2SCharles.Forsyth 	 * (sectors, secsize) can't change once the drive has
51574a4d8c2SCharles.Forsyth 	 * been brought online.
51674a4d8c2SCharles.Forsyth 	 */
51774a4d8c2SCharles.Forsyth 	bno = (off/unit->secsize) + pp->start;
51874a4d8c2SCharles.Forsyth 	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
51974a4d8c2SCharles.Forsyth 	max = SDmaxio/unit->secsize;
52074a4d8c2SCharles.Forsyth 	if(nb > max)
52174a4d8c2SCharles.Forsyth 		nb = max;
52274a4d8c2SCharles.Forsyth 	if(bno+nb > pp->end)
52374a4d8c2SCharles.Forsyth 		nb = pp->end - bno;
52474a4d8c2SCharles.Forsyth 	if(bno >= pp->end || nb == 0){
52574a4d8c2SCharles.Forsyth 		qunlock(&unit->ctl);
52674a4d8c2SCharles.Forsyth 		return 0;
52774a4d8c2SCharles.Forsyth 	}
52874a4d8c2SCharles.Forsyth 	if(!(unit->inquiry[1] & 0x80))
52974a4d8c2SCharles.Forsyth 		qunlock(&unit->ctl);
53074a4d8c2SCharles.Forsyth 
53174a4d8c2SCharles.Forsyth 	if(bsz < nb*unit->secsize){
53274a4d8c2SCharles.Forsyth 		b = malloc(nb*unit->secsize);
53374a4d8c2SCharles.Forsyth 		bsz = nb*unit->secsize;
53474a4d8c2SCharles.Forsyth 	}
53574a4d8c2SCharles.Forsyth //	b = sdmalloc(nb*unit->secsize);
53674a4d8c2SCharles.Forsyth //	if(b == nil)
53774a4d8c2SCharles.Forsyth //		return 0;
53874a4d8c2SCharles.Forsyth 
53974a4d8c2SCharles.Forsyth 	offset = off%unit->secsize;
54074a4d8c2SCharles.Forsyth 	if((l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno)) < 0) {
54174a4d8c2SCharles.Forsyth //		sdfree(b);
54274a4d8c2SCharles.Forsyth 		return 0;
54374a4d8c2SCharles.Forsyth 	}
54474a4d8c2SCharles.Forsyth 
54574a4d8c2SCharles.Forsyth 	if(l < offset)
54674a4d8c2SCharles.Forsyth 		len = 0;
54774a4d8c2SCharles.Forsyth 	else if(len > l - offset)
54874a4d8c2SCharles.Forsyth 		len = l - offset;
54974a4d8c2SCharles.Forsyth 	if(len)
55074a4d8c2SCharles.Forsyth 		memmove(a, b+offset, len);
55174a4d8c2SCharles.Forsyth //	sdfree(b);
55274a4d8c2SCharles.Forsyth 
55374a4d8c2SCharles.Forsyth 	if(unit->inquiry[1] & 0x80)
55474a4d8c2SCharles.Forsyth 		qunlock(&unit->ctl);
55574a4d8c2SCharles.Forsyth 
55674a4d8c2SCharles.Forsyth 	return len;
55774a4d8c2SCharles.Forsyth }
55874a4d8c2SCharles.Forsyth 
55974a4d8c2SCharles.Forsyth #ifdef DMA
56074a4d8c2SCharles.Forsyth long
sdrio(SDreq * r,void * a,long n)56174a4d8c2SCharles.Forsyth sdrio(SDreq *r, void* a, long n)
56274a4d8c2SCharles.Forsyth {
56374a4d8c2SCharles.Forsyth 	if(n >= SDmaxio || n < 0)
56474a4d8c2SCharles.Forsyth 		return 0;
56574a4d8c2SCharles.Forsyth 
56674a4d8c2SCharles.Forsyth 	r->data = nil;
56774a4d8c2SCharles.Forsyth 	if(n){
56874a4d8c2SCharles.Forsyth 		if((r->data = malloc(n)) == nil)
56974a4d8c2SCharles.Forsyth 			return 0;
57074a4d8c2SCharles.Forsyth 		if(r->write)
57174a4d8c2SCharles.Forsyth 			memmove(r->data, a, n);
57274a4d8c2SCharles.Forsyth 	}
57374a4d8c2SCharles.Forsyth 	r->dlen = n;
57474a4d8c2SCharles.Forsyth 
57574a4d8c2SCharles.Forsyth 	if(r->unit->dev->ifc->rio(r) != SDok){
57674a4d8c2SCharles.Forsyth // cgascreenputs("1", 1);
57774a4d8c2SCharles.Forsyth 		if(r->data != nil){
57874a4d8c2SCharles.Forsyth 			sdfree(r->data);
57974a4d8c2SCharles.Forsyth 			r->data = nil;
58074a4d8c2SCharles.Forsyth 		}
58174a4d8c2SCharles.Forsyth 		return 0;
58274a4d8c2SCharles.Forsyth 	}
58374a4d8c2SCharles.Forsyth // cgascreenputs("2", 1);
58474a4d8c2SCharles.Forsyth 
58574a4d8c2SCharles.Forsyth 	if(!r->write && r->rlen > 0)
58674a4d8c2SCharles.Forsyth 		memmove(a, r->data, r->rlen);
58774a4d8c2SCharles.Forsyth // cgascreenputs("3", 1);
58874a4d8c2SCharles.Forsyth 	if(r->data != nil){
58974a4d8c2SCharles.Forsyth 		sdfree(r->data);
59074a4d8c2SCharles.Forsyth 		r->data = nil;
59174a4d8c2SCharles.Forsyth 	}
59274a4d8c2SCharles.Forsyth 
59374a4d8c2SCharles.Forsyth // cgascreenputs("4", 1);
59474a4d8c2SCharles.Forsyth 	return r->rlen;
59574a4d8c2SCharles.Forsyth }
59674a4d8c2SCharles.Forsyth #endif /* DMA */
59774a4d8c2SCharles.Forsyth 
59874a4d8c2SCharles.Forsyth void
sleep(void *,int (* fn)(void *),void * v)59974a4d8c2SCharles.Forsyth sleep(void*, int (*fn)(void*), void *v)
60074a4d8c2SCharles.Forsyth {
60174a4d8c2SCharles.Forsyth 	int x;
60274a4d8c2SCharles.Forsyth 	x = spllo();
60374a4d8c2SCharles.Forsyth 	while(!fn(v))
60474a4d8c2SCharles.Forsyth 		;
60574a4d8c2SCharles.Forsyth 	splx(x);
60674a4d8c2SCharles.Forsyth 	return;
60774a4d8c2SCharles.Forsyth }
60874a4d8c2SCharles.Forsyth 
60974a4d8c2SCharles.Forsyth void
tsleep(void *,int (* fn)(void *),void * v,int msec)61074a4d8c2SCharles.Forsyth tsleep(void*, int (*fn)(void*), void *v, int msec)
61174a4d8c2SCharles.Forsyth {
61274a4d8c2SCharles.Forsyth 	int x;
61374a4d8c2SCharles.Forsyth 	ulong start;
61474a4d8c2SCharles.Forsyth 
61574a4d8c2SCharles.Forsyth 	x = spllo();
61674a4d8c2SCharles.Forsyth 	for(start = m->ticks; TK2MS(m->ticks - start) < msec
61774a4d8c2SCharles.Forsyth 		&& !fn(v); )
61874a4d8c2SCharles.Forsyth 		;
61974a4d8c2SCharles.Forsyth 	splx(x);
62074a4d8c2SCharles.Forsyth 	return;
62174a4d8c2SCharles.Forsyth }
62274a4d8c2SCharles.Forsyth 
62374a4d8c2SCharles.Forsyth void*
sdmalloc(void * p,ulong sz)62474a4d8c2SCharles.Forsyth sdmalloc(void *p, ulong sz)
62574a4d8c2SCharles.Forsyth {
62674a4d8c2SCharles.Forsyth 	if(p != nil) {
62774a4d8c2SCharles.Forsyth 		memset(p, 0, sz);
62874a4d8c2SCharles.Forsyth 		return p;
62974a4d8c2SCharles.Forsyth 	}
63074a4d8c2SCharles.Forsyth 	return malloc(sz);
63174a4d8c2SCharles.Forsyth }
632