Make AHCI less chatty at boot.
[akaros.git] / kern / drivers / dev / pipe.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42
43 struct dev pipedevtab;
44
45 static char *devname(void)
46 {
47         return pipedevtab.name;
48 }
49
50 typedef struct Pipe Pipe;
51 struct Pipe {
52         qlock_t qlock;
53         Pipe *next;
54         struct kref ref;
55         uint32_t path;
56         struct queue *q[2];
57         int qref[2];
58         struct dirtab *pipedir;
59         char *user;
60         struct fdtap_slist data_taps[2];
61         spinlock_t tap_lock;
62 };
63
64 static struct {
65         spinlock_t lock;
66         uint32_t path;
67         int pipeqsize;
68 } pipealloc;
69
70 enum {
71         Qdir,
72         Qdata0,
73         Qdata1,
74 };
75
76 static
77 struct dirtab pipedir[] = {
78         {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
79         {"data", {Qdata0}, 0, 0660},
80         {"data1", {Qdata1}, 0, 0660},
81 };
82
83 static void freepipe(Pipe * p)
84 {
85         if (p != NULL) {
86                 kfree(p->user);
87                 kfree(p->q[0]);
88                 kfree(p->q[1]);
89                 kfree(p->pipedir);
90                 kfree(p);
91         }
92 }
93
94 static void pipe_release(struct kref *kref)
95 {
96         Pipe *pipe = container_of(kref, Pipe, ref);
97         freepipe(pipe);
98 }
99
100 static void pipeinit(void)
101 {
102         pipealloc.pipeqsize = 32 * 1024;
103 }
104
105 /*
106  *  create a pipe, no streams are created until an open
107  */
108 static struct chan *pipeattach(char *spec)
109 {
110         ERRSTACK(2);
111         Pipe *p;
112         struct chan *c;
113
114         c = devattach(devname(), spec);
115         p = kzmalloc(sizeof(Pipe), 0);
116         if (p == 0)
117                 error(ENOMEM, ERROR_FIXME);
118         if (waserror()) {
119                 freepipe(p);
120                 nexterror();
121         }
122         p->pipedir = kzmalloc(sizeof(pipedir), 0);
123         if (p->pipedir == 0)
124                 error(ENOMEM, ERROR_FIXME);
125         memmove(p->pipedir, pipedir, sizeof(pipedir));
126         kstrdup(&p->user, current->user);
127         kref_init(&p->ref, pipe_release, 1);
128         qlock_init(&p->qlock);
129
130         p->q[0] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
131         if (p->q[0] == 0)
132                 error(ENOMEM, ERROR_FIXME);
133         p->q[1] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
134         if (p->q[1] == 0)
135                 error(ENOMEM, ERROR_FIXME);
136         poperror();
137
138         spin_lock(&(&pipealloc)->lock);
139         p->path = ++pipealloc.path;
140         spin_unlock(&(&pipealloc)->lock);
141
142         c->qid.path = NETQID(2 * p->path, Qdir);
143         c->qid.vers = 0;
144         c->qid.type = QTDIR;
145         c->aux = p;
146         c->dev = 0;
147
148         /* taps. */
149         SLIST_INIT(&p->data_taps[0]);   /* already = 0; set to be futureproof */
150         SLIST_INIT(&p->data_taps[1]);
151         spinlock_init(&p->tap_lock);
152         return c;
153 }
154
155 static int
156 pipegen(struct chan *c, char *unused,
157                 struct dirtab *tab, int ntab, int i, struct dir *dp)
158 {
159         int id, len;
160         struct qid qid;
161         Pipe *p;
162
163         if (i == DEVDOTDOT) {
164                 devdir(c, c->qid, devname(), 0, eve, 0555, dp);
165                 return 1;
166         }
167         i++;    /* skip . */
168         if (tab == 0 || i >= ntab)
169                 return -1;
170         tab += i;
171         p = c->aux;
172         switch (NETTYPE(tab->qid.path)) {
173                 case Qdata0:
174                         len = qlen(p->q[0]);
175                         break;
176                 case Qdata1:
177                         len = qlen(p->q[1]);
178                         break;
179                 default:
180                         len = tab->length;
181                         break;
182         }
183         id = NETID(c->qid.path);
184         qid.path = NETQID(id, tab->qid.path);
185         qid.vers = 0;
186         qid.type = QTFILE;
187         devdir(c, qid, tab->name, len, eve, tab->perm, dp);
188         return 1;
189 }
190
191 static struct walkqid *pipewalk(struct chan *c, struct chan *nc, char **name,
192                                                                 int nname)
193 {
194         struct walkqid *wq;
195         Pipe *p;
196
197         p = c->aux;
198         wq = devwalk(c, nc, name, nname, p->pipedir, ARRAY_SIZE(pipedir), pipegen);
199         if (wq != NULL && wq->clone != NULL && wq->clone != c) {
200                 qlock(&p->qlock);
201                 kref_get(&p->ref, 1);
202                 if (c->flag & COPEN) {
203                         switch (NETTYPE(c->qid.path)) {
204                                 case Qdata0:
205                                         p->qref[0]++;
206                                         break;
207                                 case Qdata1:
208                                         p->qref[1]++;
209                                         break;
210                         }
211                 }
212                 qunlock(&p->qlock);
213         }
214         return wq;
215 }
216
217 static int pipestat(struct chan *c, uint8_t * db, int n)
218 {
219         Pipe *p;
220         struct dir dir;
221         struct dirtab *tab;
222         int perm;
223
224         p = c->aux;
225         tab = p->pipedir;
226
227         switch (NETTYPE(c->qid.path)) {
228                 case Qdir:
229                         devdir(c, c->qid, ".", 0, eve, DMDIR | 0555, &dir);
230                         break;
231                 case Qdata0:
232                         perm = tab[1].perm;
233                         perm |= qreadable(p->q[0]) ? DMREADABLE : 0;
234                         perm |= qwritable(p->q[0]) ? DMWRITABLE : 0;
235                         devdir(c, c->qid, tab[1].name, qlen(p->q[0]), eve, perm, &dir);
236                         break;
237                 case Qdata1:
238                         perm = tab[2].perm;
239                         perm |= qreadable(p->q[1]) ? DMREADABLE : 0;
240                         perm |= qwritable(p->q[1]) ? DMWRITABLE : 0;
241                         devdir(c, c->qid, tab[2].name, qlen(p->q[1]), eve, perm, &dir);
242                         break;
243                 default:
244                         panic("pipestat");
245         }
246         n = convD2M(&dir, db, n);
247         if (n < BIT16SZ)
248                 error(ENODATA, ERROR_FIXME);
249         return n;
250 }
251
252 /*
253  *  if the stream doesn't exist, create it
254  */
255 static struct chan *pipeopen(struct chan *c, int omode)
256 {
257         ERRSTACK(2);
258         Pipe *p;
259
260         if (c->qid.type & QTDIR) {
261                 if (omode & O_WRITE)
262                         error(EINVAL, "Can only open directories O_READ, mode is %o oct",
263                                   omode);
264                 c->mode = openmode(omode);
265                 c->flag |= COPEN;
266                 c->offset = 0;
267                 return c;
268         }
269
270         openmode(omode);        /* check it */
271
272         p = c->aux;
273         qlock(&p->qlock);
274         if (waserror()) {
275                 qunlock(&p->qlock);
276                 nexterror();
277         }
278         switch (NETTYPE(c->qid.path)) {
279                 case Qdata0:
280                         devpermcheck(p->user, p->pipedir[1].perm, omode);
281                         p->qref[0]++;
282                         break;
283                 case Qdata1:
284                         devpermcheck(p->user, p->pipedir[2].perm, omode);
285                         p->qref[1]++;
286                         break;
287         }
288         poperror();
289         qunlock(&p->qlock);
290
291         c->mode = openmode(omode);
292         c->flag |= COPEN;
293         c->offset = 0;
294         c->iounit = qiomaxatomic;
295         return c;
296 }
297
298 static void pipeclose(struct chan *c)
299 {
300         Pipe *p;
301
302         p = c->aux;
303         qlock(&p->qlock);
304
305         if (c->flag & COPEN) {
306                 /*
307                  *  closing either side hangs up the stream
308                  */
309                 switch (NETTYPE(c->qid.path)) {
310                         case Qdata0:
311                                 p->qref[0]--;
312                                 if (p->qref[0] == 0) {
313                                         qhangup(p->q[1], 0);
314                                         qclose(p->q[0]);
315                                 }
316                                 break;
317                         case Qdata1:
318                                 p->qref[1]--;
319                                 if (p->qref[1] == 0) {
320                                         qhangup(p->q[0], 0);
321                                         qclose(p->q[1]);
322                                 }
323                                 break;
324                 }
325         }
326
327         /*
328          *  if both sides are closed, they are reusable
329          */
330         if (p->qref[0] == 0 && p->qref[1] == 0) {
331                 qreopen(p->q[0]);
332                 qreopen(p->q[1]);
333         }
334
335         qunlock(&p->qlock);
336         /*
337          *  free the structure on last close
338          */
339         kref_put(&p->ref);
340 }
341
342 static long piperead(struct chan *c, void *va, long n, int64_t ignored)
343 {
344         Pipe *p;
345
346         p = c->aux;
347
348         switch (NETTYPE(c->qid.path)) {
349                 case Qdir:
350                         return devdirread(c, va, n, p->pipedir, ARRAY_SIZE(pipedir),
351                                                           pipegen);
352                 case Qdata0:
353                         if (c->flag & O_NONBLOCK)
354                                 return qread_nonblock(p->q[0], va, n);
355                         else
356                                 return qread(p->q[0], va, n);
357                 case Qdata1:
358                         if (c->flag & O_NONBLOCK)
359                                 return qread_nonblock(p->q[1], va, n);
360                         else
361                                 return qread(p->q[1], va, n);
362                 default:
363                         panic("piperead");
364         }
365         return -1;      /* not reached */
366 }
367
368 static struct block *pipebread(struct chan *c, long n, uint32_t offset)
369 {
370         Pipe *p;
371
372         p = c->aux;
373
374         switch (NETTYPE(c->qid.path)) {
375                 case Qdata0:
376                         if (c->flag & O_NONBLOCK)
377                                 return qbread_nonblock(p->q[0], n);
378                         else
379                                 return qbread(p->q[0], n);
380                 case Qdata1:
381                         if (c->flag & O_NONBLOCK)
382                                 return qbread_nonblock(p->q[1], n);
383                         else
384                                 return qbread(p->q[1], n);
385         }
386
387         return devbread(c, n, offset);
388 }
389
390 /*
391  *  A write to a closed pipe causes an EPIPE error to be thrown.
392  */
393 static long pipewrite(struct chan *c, void *va, long n, int64_t ignored)
394 {
395         Pipe *p;
396         //Prog *r;
397
398         p = c->aux;
399
400         switch (NETTYPE(c->qid.path)) {
401                 case Qdata0:
402                         if (c->flag & O_NONBLOCK)
403                                 n = qwrite_nonblock(p->q[1], va, n);
404                         else
405                                 n = qwrite(p->q[1], va, n);
406                         break;
407
408                 case Qdata1:
409                         if (c->flag & O_NONBLOCK)
410                                 n = qwrite_nonblock(p->q[0], va, n);
411                         else
412                                 n = qwrite(p->q[0], va, n);
413                         break;
414
415                 default:
416                         panic("pipewrite");
417         }
418
419         return n;
420 }
421
422 static long pipebwrite(struct chan *c, struct block *bp, uint32_t junk)
423 {
424         long n;
425         Pipe *p;
426         //Prog *r;
427
428         p = c->aux;
429         switch (NETTYPE(c->qid.path)) {
430                 case Qdata0:
431                         if (c->flag & O_NONBLOCK)
432                                 n = qbwrite_nonblock(p->q[1], bp);
433                         else
434                                 n = qbwrite(p->q[1], bp);
435                         break;
436
437                 case Qdata1:
438                         if (c->flag & O_NONBLOCK)
439                                 n = qbwrite_nonblock(p->q[0], bp);
440                         else
441                                 n = qbwrite(p->q[0], bp);
442                         break;
443
444                 default:
445                         n = 0;
446                         panic("pipebwrite");
447         }
448
449         return n;
450 }
451
452 static int pipewstat(struct chan *c, uint8_t *dp, int n)
453 {
454         ERRSTACK(2);
455         struct dir *d;
456         Pipe *p;
457         int d1;
458
459         if (c->qid.type & QTDIR)
460                 error(EPERM, ERROR_FIXME);
461         p = c->aux;
462         if (strcmp(current->user, p->user) != 0)
463                 error(EPERM, ERROR_FIXME);
464         d = kzmalloc(sizeof(*d) + n, 0);
465         if (waserror()) {
466                 kfree(d);
467                 nexterror();
468         }
469         n = convM2D(dp, n, d, (char *)&d[1]);
470         if (n == 0)
471                 error(ENODATA, ERROR_FIXME);
472         d1 = NETTYPE(c->qid.path) == Qdata1;
473         if (!emptystr(d->name)) {
474                 validwstatname(d->name);
475                 if (strlen(d->name) >= KNAMELEN)
476                         error(ENAMETOOLONG, ERROR_FIXME);
477                 if (strncmp(p->pipedir[1 + !d1].name, d->name, KNAMELEN) == 0)
478                         error(EEXIST, ERROR_FIXME);
479                 strncpy(p->pipedir[1 + d1].name, d->name, KNAMELEN);
480         }
481         if (d->mode != ~0UL)
482                 p->pipedir[d1 + 1].perm = d->mode & 0777;
483         poperror();
484         kfree(d);
485         return n;
486 }
487
488 static void pipe_wake_cb(struct queue *q, void *data, int filter)
489 {
490         /* If you allocate structs like this on odd byte boundaries, you
491          * deserve what you get.  */
492         uintptr_t kludge = (uintptr_t) data;
493         int which = kludge & 1;
494         Pipe *p = (Pipe*)(kludge & ~1ULL);
495         struct fd_tap *tap_i;
496
497         spin_lock(&p->tap_lock);
498         SLIST_FOREACH(tap_i, &p->data_taps[which], link)
499                 fire_tap(tap_i, filter);
500         spin_unlock(&p->tap_lock);
501 }
502
503 static int pipetapfd(struct chan *chan, struct fd_tap *tap, int cmd)
504 {
505         int ret;
506         Pipe *p;
507         int which = 1;
508         uint64_t kludge;
509
510         p = chan->aux;
511         kludge = (uint64_t)p;
512 #define DEVPIPE_LEGAL_DATA_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_WRITABLE | \
513                                  FDTAP_FILT_HANGUP | FDTAP_FILT_ERROR)
514
515         switch (NETTYPE(chan->qid.path)) {
516         case Qdata0:
517                 which = 0;
518                 /* fall through */
519         case Qdata1:
520                 kludge |= which;
521
522                 if (tap->filter & ~DEVPIPE_LEGAL_DATA_TAPS) {
523                         set_errno(ENOSYS);
524                         set_errstr("Unsupported #%s data tap %p, must be %p", devname(),
525                                    tap->filter, DEVPIPE_LEGAL_DATA_TAPS);
526                         return -1;
527                 }
528                 spin_lock(&p->tap_lock);
529                 switch (cmd) {
530                 case (FDTAP_CMD_ADD):
531                         if (SLIST_EMPTY(&p->data_taps[which]))
532                                 qio_set_wake_cb(p->q[which], pipe_wake_cb, (void *)kludge);
533                         SLIST_INSERT_HEAD(&p->data_taps[which], tap, link);
534                         ret = 0;
535                         break;
536                 case (FDTAP_CMD_REM):
537                         SLIST_REMOVE(&p->data_taps[which], tap, fd_tap, link);
538                         if (SLIST_EMPTY(&p->data_taps[which]))
539                                 qio_set_wake_cb(p->q[which], 0, (void *)kludge);
540                         ret = 0;
541                         break;
542                 default:
543                         set_errno(ENOSYS);
544                         set_errstr("Unsupported #%s data tap command %p", devname(), cmd);
545                         ret = -1;
546                 }
547                 spin_unlock(&p->tap_lock);
548                 return ret;
549         default:
550                 set_errno(ENOSYS);
551                 set_errstr("Can't tap #%s file type %d", devname(),
552                            NETTYPE(chan->qid.path));
553                 return -1;
554         }
555 }
556
557 struct dev pipedevtab __devtab = {
558         .name = "pipe",
559
560         .reset = devreset,
561         .init = pipeinit,
562         .shutdown = devshutdown,
563         .attach = pipeattach,
564         .walk = pipewalk,
565         .stat = pipestat,
566         .open = pipeopen,
567         .create = devcreate,
568         .close = pipeclose,
569         .read = piperead,
570         .bread = pipebread,
571         .write = pipewrite,
572         .bwrite = pipebwrite,
573         .remove = devremove,
574         .wstat = pipewstat,
575         .power = devpower,
576         .chaninfo = devchaninfo,
577         .tapfd = pipetapfd,
578 };