9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

devblk.c (4797B)


      1 #include <errno.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include <os9/os9.h>
      6 
      7 #include "dev.h"
      8 #include "blk.h"
      9 
     10 #define NR_BLOCKS  1
     11 #define NR_BLKS     2
     12 
     13 typedef struct buffer Buffer;
     14 
     15 enum Odevqid {
     16 	Qblockfs,
     17 	Qraw,
     18 	Qctl,
     19 };
     20 
     21 enum bstatus {
     22 	BBUSY  = 1 << 0,
     23 	BDIRTY = 1 << 1,
     24 	BVALID = 1 << 2,
     25 	BERROR = 1 << 3,
     26 };
     27 
     28 struct buffer {
     29 	int devno;
     30 	long block;
     31 	int flags;
     32 	void *ptr;
     33 	mutex_t mutex;
     34 };
     35 
     36 static char buffers[NR_BLOCKS][BLKSIZ];
     37 static Buffer bcache[NR_BLOCKS];
     38 
     39 static Dirtab dirtab[] = {
     40 	{"raw", QID(CHFILE, 0, Qraw), 0, O_READ | O_WRITE},
     41 	{"ctl", QID(CHFILE, 0, Qctl), 0, O_READ | O_WRITE}
     42 };
     43 
     44 static Blk *blks[NR_BLKS];
     45 static int nblks;
     46 
     47 static int
     48 blkwalk(Chan *c, char *name)
     49 {
     50 	return devwalk(c, name, dirtab, NELEM(dirtab), devgen);
     51 }
     52 
     53 static int
     54 blkstat(Chan *c, char *file, unsigned char *buf, int n)
     55 {
     56 	return devstat(c, file, buf, n, dirtab, NELEM(dirtab), devgen);
     57 }
     58 
     59 static Buffer *
     60 getblk(int devno, long blkno)
     61 {
     62 	Buffer *bp = &bcache[blkno % NR_BLOCKS];
     63 	Blk *dev;
     64 
     65 repeat:
     66 	lock(&bp->mutex);
     67 	if (bp->flags & BBUSY) {
     68 		unlock(&bp->mutex);
     69 		/* TODO: sleep(); */
     70 		goto repeat;
     71 	}
     72 
     73 	if ((bp->flags & BVALID) == 0 ||
     74 	    bp->devno != devno || bp->block != blkno) {
     75 		if (bp->flags & BDIRTY) {
     76 			dev = blks[bp->devno];
     77 			if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) {
     78 				seterror(EIO);
     79 				bp->flags |= BERROR;
     80 				goto return_buffer;
     81 			}
     82 		}
     83 
     84 		bp->devno = devno;
     85 		bp->block = blkno;
     86 		bp->flags = 0;
     87 		dev = blks[devno];
     88 
     89 		switch (dev->phy->bread(dev, blkno, bp->ptr)) {
     90 		case -1:
     91 			bp->flags |= BERROR;
     92 			break;
     93 		case 0:
     94 			// EOF: no flag set
     95 			break;
     96 		default:
     97 			bp->flags |= BVALID;
     98 			break;
     99 		}
    100 	}
    101 
    102 return_buffer:
    103 	bp->flags |= BBUSY;
    104 	unlock(&bp->mutex);
    105 	return bp;
    106 }
    107 
    108 static int
    109 brelse(Buffer *bp)
    110 {
    111 	int r = 0;
    112 	Blk *dev;
    113 
    114 	if ((bp->flags & BBUSY) == 0)
    115 		panic("brelse");
    116 
    117 	lock(&bp->mutex);
    118 	if ((bp->flags & BDIRTY) != 0) {
    119 		dev = blks[bp->devno];
    120 		if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) {
    121 			seterror(EIO);
    122 			bp->flags |= BERROR;
    123 			r = -1;
    124 		}
    125 	}
    126 	bp->flags &= ~(BBUSY|BDIRTY);
    127 	unlock(&bp->mutex);
    128 
    129 	return r;
    130 }
    131 
    132 static int
    133 rawread(Chan *c, void *buf, int nbytes)
    134 {
    135 	int n, cnt;
    136 	Buffer *bp;
    137 	long off, blk;
    138 	char *ptr = buf;
    139 
    140 	for (cnt = 0; cnt < nbytes; cnt += n) {
    141 		blk = c->offset / BLKSIZ;
    142 		off = c->offset % BLKSIZ;
    143 
    144 		bp = getblk(c->dev, blk);
    145 		switch (bp->flags & (BVALID | BERROR)) {
    146 		case BVALID|BERROR:
    147 		case BERROR:
    148 			cnt = -1;
    149 		case 0:
    150 			brelse(bp);
    151 			return cnt;
    152 		case BVALID:
    153 			n = BLKSIZ - off;
    154 			if (n > nbytes)
    155 				n = nbytes;
    156 			memcpy(ptr, bp->ptr + off, n);
    157 			ptr += n;
    158 			c->offset += n;
    159 			brelse(bp);
    160 			break;
    161 		}
    162 	}
    163 
    164 	return cnt;
    165 }
    166 
    167 static int
    168 blkread(Chan *c, void *buf, int n)
    169 {
    170 	switch (c->qid.path) {
    171 	case Qblockfs:
    172 		return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen);
    173 	case Qraw:
    174 		return rawread(c, buf, n);
    175 	case Qctl:
    176 		/* TODO */
    177 	default:
    178 		panic("blkread");
    179 	}
    180 }
    181 
    182 static int
    183 rawwrite(Chan *c, void *buf, int nbytes)
    184 {
    185 	int n, cnt;
    186 	Buffer *bp;
    187 	long off, blk;
    188 	char *ptr = buf;
    189 
    190 	for (cnt = 0; cnt < nbytes; cnt += n) {
    191 		blk = c->offset / BLKSIZ;
    192 		off = c->offset % BLKSIZ;
    193 
    194 		bp = getblk(c->dev, blk);
    195 		switch (bp->flags & (BVALID | BERROR)) {
    196 		case 0:
    197 			seterror(EFBIG);
    198 		case BVALID|BERROR:
    199 		case BERROR:
    200 			brelse(bp);
    201 			return -1;
    202 		case BVALID:
    203 			n = BLKSIZ - off;
    204 			if (n > nbytes - cnt)
    205 				n = nbytes - cnt;
    206 			memcpy(bp->ptr + off, ptr, n);
    207 			ptr += n;
    208 			c->offset += n;
    209 			bp->flags |= BDIRTY;
    210 			brelse(bp);
    211 			break;
    212 		}
    213 	}
    214 	return cnt;
    215 }
    216 
    217 static int
    218 blkwrite(Chan *c, void *buf, int n)
    219 {
    220 	switch (c->qid.path) {
    221 	case Qraw:
    222 		return rawwrite(c, buf, n);
    223 	case Qctl:
    224 		/* TODO */
    225 	default:
    226 		panic("blkwrite");
    227 	}
    228 }
    229 
    230 static int
    231 blksync(Chan *c, int what)
    232 {
    233 	Blk *dev;
    234 	Buffer *bp;
    235 	int r = 0;
    236 
    237 	for (bp = bcache; bp < &bcache[NR_BLOCKS]; ++bp) {
    238 		lock(&bp->mutex);
    239 
    240 		if ((bp->flags & BDIRTY) != 0 &&
    241 		    (what == SYNCALL || bp->devno == c->dev)) {
    242 			dev = blks[bp->devno];
    243 			if (dev->phy->bwrite(dev, bp->block, bp->ptr) < 0) {
    244 				r = -1;
    245 				seterror(EIO);
    246 				bp->flags |= BERROR;
    247 			} else {
    248 				bp->flags &= BDIRTY;
    249 			}
    250 		}
    251 
    252 		unlock(&bp->mutex);
    253 	}
    254 
    255 	return r;
    256 }
    257 
    258 void
    259 blklink(Blkphy *phy, Attr *attr)
    260 {
    261 	size_t siz;
    262 	Blk *dev;
    263 	static int first = 1;
    264 
    265 	if (nblks == NR_BLKS)
    266 		panic("blklink");
    267 
    268 	if (first) {
    269 		int i;
    270 		Buffer *bp;
    271 
    272 		for (i = 0; i < NR_BLOCKS; i++) {
    273 			bp = &bcache[i];
    274 			bp->ptr = buffers[i];
    275 			bp->flags = 0;
    276 		}
    277 		first = 0;
    278 	}
    279 
    280 	siz = sizeof(Blk);
    281 	dev = memset(alloc(siz), 0, siz);
    282 	dev->phy = phy;
    283 	blks[nblks++] = dev;
    284 
    285 	(*phy->init)(dev, attr);
    286 }
    287 
    288 Dev blkdevtab = {
    289 	.id = 'b',
    290 	.stat = blkstat,
    291 	.clone = devclone,
    292 	.attach = devattach,
    293 	.walk = blkwalk,
    294 	.read = blkread,
    295 	.write = blkwrite,
    296 	.mount = deverrmount,
    297 	.seek = devseek,
    298 	.sync = blksync,
    299 	.close = devclose,
    300 };