|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "devtab.h"
8: #include "io.h"
9:
10: #define DATASIZE (8*1024)
11:
12: typedef struct Partition Partition;
13: typedef struct Drive Drive;
14:
15: enum {
16: Npart= 8+2, /* 8 sub partitions, disk, and partition */
17: Ndisk= 64, /* maximum disks; if you change it, you must
18: map from dev to disk */
19:
20: /* file types */
21: Qdir= 0,
22: };
23: #define PART(x) ((x)&0xF)
24: #define DRIVE(x) (((x)>>4)&(Ndisk-1))
25: #define MKQID(d,p) (((d)<<4) | (p))
26:
27: struct Partition
28: {
29: ulong start;
30: ulong end;
31: char name[NAMELEN+1];
32: };
33:
34: struct Drive
35: {
36: QLock;
37: ulong bytes; /* bytes per block */
38: int npart; /* actual number of partitions */
39: int drive;
40: int readonly;
41: Partition p[Npart];
42: };
43:
44: static Drive wren[Ndisk];
45:
46: static void wrenpart(int);
47: static long wrenio(Chan*, int, char*, ulong, ulong);
48:
49: /*
50: * accepts [0-7].[0-7], or abbreviation
51: */
52: static int
53: wrendev(char *p)
54: {
55: int drive, unit;
56:
57: if(p == 0 || p[0] == '\0')
58: return 0;
59: if(p[0] < '0' || p[0] > '7')
60: error(Ebadarg);
61: drive = p[0] - '0';
62: unit = 0;
63: if(p[1]){
64: if(p[1] != '.' || p[2] < '0' || p[2] > '7' || p[3] != '\0')
65: error(Ebadarg);
66: unit = p[2] - '0';
67: }
68: return (drive << 3) | unit;
69: }
70:
71: static int
72: wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
73: {
74: Qid qid;
75: int drive;
76: char name[NAMELEN+4];
77: Drive *dp;
78: Partition *pp;
79: ulong l;
80:
81: USED(tab, ntab);
82: qid.vers = 0;
83: drive = c->dev;
84: if(drive >= Ndisk)
85: return -1;
86: dp = &wren[drive];
87:
88: if(s >= dp->npart)
89: return -1;
90:
91: pp = &dp->p[s];
92: if(drive & 7)
93: sprint(name, "sd%d.%d%s", drive>>3, drive&7, pp->name);
94: else
95: sprint(name, "sd%d%s", drive>>3, pp->name);
96: name[NAMELEN] = 0;
97: qid.path = MKQID(drive, s);
98: l = (pp->end - pp->start) * dp->bytes;
99: devdir(c, qid, name, l, eve, dp->readonly ? 0444 : 0666, dirp);
100: return 1;
101: }
102:
103: void
104: wrenreset(void)
105: {
106: }
107:
108: void
109: wreninit(void)
110: {
111: }
112:
113: /*
114: * param is #w<target>.<lun>
115: */
116: Chan *
117: wrenattach(char *param)
118: {
119: Chan *c;
120: int drive;
121:
122: drive = wrendev(param);
123: wrenpart(drive);
124: c = devattach('w', param);
125: c->dev = drive;
126: return c;
127: }
128:
129: Chan*
130: wrenclone(Chan *c, Chan *nc)
131: {
132: return devclone(c, nc);
133: }
134:
135: int
136: wrenwalk(Chan *c, char *name)
137: {
138: return devwalk(c, name, 0, 0, wrengen);
139: }
140:
141: void
142: wrenstat(Chan *c, char *dp)
143: {
144: devstat(c, dp, 0, 0, wrengen);
145: }
146:
147: Chan*
148: wrenopen(Chan *c, int omode)
149: {
150: return devopen(c, omode, 0, 0, wrengen);
151: }
152:
153: void
154: wrencreate(Chan *c, char *name, int omode, ulong perm)
155: {
156: USED(c, name, omode, perm);
157: error(Eperm);
158: }
159:
160: void
161: wrenclose(Chan *c)
162: {
163: Drive *d;
164: Partition *p;
165:
166: if(c->mode != OWRITE && c->mode != ORDWR)
167: return;
168:
169: d = &wren[DRIVE(c->qid.path)];
170: p = &d->p[PART(c->qid.path)];
171: if(strcmp(p->name, "partition"))
172: return;
173:
174: wrenpart(DRIVE(c->qid.path));
175: }
176:
177: void
178: wrenremove(Chan *c)
179: {
180: USED(c);
181: error(Eperm);
182: }
183:
184: void
185: wrenwstat(Chan *c, char *dp)
186: {
187: USED(c, dp);
188: error(Eperm);
189: }
190:
191: long
192: wrenread(Chan *c, char *a, long n, ulong offset)
193: {
194: if(c->qid.path == CHDIR)
195: return devdirread(c, a, n, 0, 0, wrengen);
196: return wrenio(c, 0, a, n, offset);
197: }
198:
199: long
200: wrenwrite(Chan *c, char *a, long n, ulong offset)
201: {
202: n = wrenio(c, 1, a, n, offset);
203: if(n)
204: return n;
205: error("end of device");
206: return 0; /* not reached */
207: }
208:
209: static long
210: wrenio(Chan *c, int write, char *a, ulong len, ulong offset)
211: {
212: Drive *d;
213: Partition *p;
214: Scsibuf *b;
215: ulong block, n, max, x;
216: d = &wren[DRIVE(c->qid.path)];
217: if(d->npart == 0) /* drive repartitioned */
218: error(Eio);
219: p = &d->p[PART(c->qid.path)];
220:
221: block = offset / d->bytes + p->start;
222: n = (offset + len + d->bytes - 1) / d->bytes + p->start - block;
223: max = DATASIZE / d->bytes;
224: if(n > max)
225: n = max;
226: if(block + n > p->end)
227: n = p->end - block;
228: if(block >= p->end || n == 0)
229: return 0;
230: b = scsibuf();
231: if(waserror()){
232: scsifree(b);
233: nexterror();
234: }
235: offset %= d->bytes;
236: if(write){
237: if(offset || len % d->bytes){
238: x = scsibread(d->drive, b, n, d->bytes, block);
239: if(x < n * d->bytes){
240: n = x / d->bytes;
241: x = n * d->bytes - offset;
242: if(len > x)
243: len = x;
244: }
245: }
246: memmove((char*)b->virt + offset, a, len);
247: x = scsibwrite(d->drive, b, n, d->bytes, block);
248: if(x < offset)
249: len = 0;
250: else if(len > x - offset)
251: len = x - offset;
252: }else{
253: x = scsibread(d->drive, b, n, d->bytes, block);
254: if(x < offset)
255: len = 0;
256: else if(len > x - offset)
257: len = x - offset;
258: if(len)
259: memmove(a, (char*)b->virt + offset, len);
260: }
261: poperror();
262: scsifree(b);
263: return len;
264: }
265:
266: /*
267: * read partition table. The partition table is just ascii strings.
268: */
269: #define MAGIC "plan9 partitions"
270: static void
271: wrenpart(int dev)
272: {
273: Drive *dp;
274: Partition *pp;
275: uchar buf[128];
276: Scsibuf *b;
277: char *rawpart, *line[Npart+1], *field[3];
278: ulong n;
279: int i;
280:
281: dp = &wren[dev];
282: if(waserror()){
283: qunlock(dp);
284: nexterror();
285: }
286: qlock(dp);
287: scsiready(dev);
288: scsisense(dev, buf);
289: scsistartstop(dev, ScsiStartunit);
290: scsisense(dev, buf);
291: if(scsicap(dev, buf))
292: error(Eio);
293: dp->drive = dev;
294: dp->readonly = scsiwp(dev);
295:
296: /*
297: * we always have a partition for the whole disk
298: * and one for the partition table
299: */
300: dp->bytes = (buf[4]<<24)+(buf[5]<<16)+(buf[6]<<8)+(buf[7]);
301: pp = &dp->p[0];
302: strcpy(pp->name, "disk");
303: pp->start = 0;
304: pp->end = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]) + 1;
305: pp++;
306: strcpy(pp->name, "partition");
307: pp->start = dp->p[0].end - 1;
308: pp->end = dp->p[0].end;
309:
310: scsiinquiry(dev, buf, sizeof buf);
311: switch(buf[0]) {
312: default:
313: error("not a SCSI disk");
314: case 0x00: /* Direct access (disk) */
315: case 0x05: /* CD-rom */
316: case 0x07: /* rewriteable MO */
317: break;
318: }
319:
320: if(memcmp(&buf[8], "INSITE I325VM *F", 24) == 0)
321: scsimodesense(dev, 0x2e, buf, 0x2a);
322: /*
323: * read partition table from disk, null terminate
324: */
325: b = scsibuf();
326: if(waserror()){
327: scsifree(b);
328: nexterror();
329: }
330: scsibread(dev, b, 1, dp->bytes, dp->p[0].end-1);
331: rawpart = b->virt;
332: rawpart[dp->bytes-1] = 0;
333:
334: /*
335: * parse partition table.
336: */
337: pp = &dp->p[2];
338: n = getfields(rawpart, line, Npart+1, "\n");
339: if(n > 0 && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
340: for(i = 1; i < n; i++){
341: if(getfields(line[i], field, 3, " ") != 3)
342: break;
343: strncpy(pp->name, field[0], NAMELEN);
344: pp->start = strtoul(field[1], 0, 0);
345: pp->end = strtoul(field[2], 0, 0);
346: if(pp->start > pp->end || pp->start >= dp->p[0].end)
347: break;
348: pp++;
349: }
350: }
351: dp->npart = pp - dp->p;
352: poperror();
353: scsifree(b);
354: poperror();
355: qunlock(dp);
356: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.