]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/ia64/ia64/sscdisk.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / ia64 / ia64 / sscdisk.c
1 /*-
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD$
10  *
11  */
12
13 #include "opt_md.h"
14 #include "opt_ski.h"
15
16 #include <sys/param.h>
17 #include <sys/systm.h>
18 #include <sys/bio.h>
19 #include <sys/conf.h>
20 #include <sys/kernel.h>
21 #include <sys/linker.h>
22 #include <sys/lock.h>
23 #include <sys/malloc.h>
24 #include <sys/mutex.h>
25 #include <sys/queue.h>
26 #include <sys/sysctl.h>
27 #include <sys/proc.h>
28 #include <vm/vm.h>
29 #include <vm/vm_kern.h>
30 #include <vm/vm_page.h>
31 #include <vm/vm_map.h>
32 #include <vm/vm_extern.h>
33 #include <vm/vm_object.h>
34 #include <vm/vm_pager.h>
35 #include <machine/md_var.h>
36 #include <geom/geom_disk.h>
37
38 #ifndef SKI_ROOT_FILESYSTEM
39 #define SKI_ROOT_FILESYSTEM     "ia64-root.fs"
40 #endif
41
42 #define SSC_OPEN                        50
43 #define SSC_CLOSE                       51
44 #define SSC_READ                        52
45 #define SSC_WRITE                       53
46 #define SSC_GET_COMPLETION              54
47 #define SSC_WAIT_COMPLETION             55
48
49 struct disk_req {
50         unsigned long addr;
51         unsigned len;
52 };
53
54 struct disk_stat {
55         int fd;
56         unsigned count;
57 };
58
59 static u_int64_t
60 ssc(u_int64_t in0, u_int64_t in1, u_int64_t in2, u_int64_t in3, int which)
61 {
62         register u_int64_t ret0 __asm("r8");
63
64         __asm __volatile("mov r15=%1\n\t"
65                          "break 0x80001"
66                          : "=r"(ret0)
67                          : "r"(which), "r"(in0), "r"(in1), "r"(in2), "r"(in3));
68         return ret0;
69 }
70
71 #ifndef SSC_NSECT
72 #define SSC_NSECT 409600
73 #endif
74
75 static MALLOC_DEFINE(M_SSC, "ssc_disk", "Simulator Disk");
76
77 static d_strategy_t sscstrategy;
78
79 static LIST_HEAD(, ssc_s) ssc_softc_list = LIST_HEAD_INITIALIZER(ssc_softc_list);
80
81 struct ssc_s {
82         int unit;
83         LIST_ENTRY(ssc_s) list;
84         struct bio_queue_head bio_queue;
85         struct disk *disk;
86         struct cdev *dev;
87         int busy;
88         int fd;
89 };
90
91 static int sscunits;
92
93 static void
94 sscstrategy(struct bio *bp)
95 {
96         struct ssc_s *sc;
97         int s;
98         struct disk_req req;
99         struct disk_stat stat;
100         u_long len, va, off;
101
102         sc = bp->bio_disk->d_drv1;
103
104         s = splbio();
105
106         bioq_disksort(&sc->bio_queue, bp);
107
108         if (sc->busy) {
109                 splx(s);
110                 return;
111         }
112
113         sc->busy++;
114         
115         while (1) {
116                 bp = bioq_takefirst(&sc->bio_queue);
117                 splx(s);
118                 if (!bp)
119                         break;
120
121                 va = (u_long) bp->bio_data;
122                 len = bp->bio_bcount;
123                 off = bp->bio_pblkno << DEV_BSHIFT;
124                 while (len > 0) {
125                         u_int t;
126                         if ((va & PAGE_MASK) + len > PAGE_SIZE)
127                                 t = PAGE_SIZE - (va & PAGE_MASK);
128                         else
129                                 t = len;
130                         req.len = t;
131                         req.addr = ia64_tpa(va);
132                         ssc(sc->fd, 1, ia64_tpa((long) &req), off,
133                             (bp->bio_cmd == BIO_READ) ? SSC_READ : SSC_WRITE);
134                         stat.fd = sc->fd;
135                         ssc(ia64_tpa((long)&stat), 0, 0, 0,
136                             SSC_WAIT_COMPLETION);
137                         va += t;
138                         len -= t;
139                         off += t;
140                 }
141                 bp->bio_resid = 0;
142                 biodone(bp);
143                 s = splbio();
144         }
145
146         sc->busy = 0;
147         return;
148 }
149
150 static struct ssc_s *
151 ssccreate(int unit)
152 {
153         struct ssc_s *sc;
154         int fd;
155
156         fd = ssc(ia64_tpa((u_int64_t) SKI_ROOT_FILESYSTEM),
157                  1, 0, 0, SSC_OPEN);
158         if (fd == -1)
159                 return (NULL);
160
161         if (unit == -1)
162                 unit = sscunits++;
163         /* Make sure this unit isn't already in action */
164         LIST_FOREACH(sc, &ssc_softc_list, list) {
165                 if (sc->unit == unit)
166                         return (NULL);
167         }
168         sc = malloc(sizeof(*sc), M_SSC, M_WAITOK | M_ZERO);
169         LIST_INSERT_HEAD(&ssc_softc_list, sc, list);
170         sc->unit = unit;
171         bioq_init(&sc->bio_queue);
172
173         sc->disk = disk_alloc();
174         sc->disk->d_drv1 = sc;
175         sc->disk->d_fwheads = 0;
176         sc->disk->d_fwsectors = 0;
177         sc->disk->d_maxsize = DFLTPHYS;
178         sc->disk->d_mediasize = (off_t)SSC_NSECT * DEV_BSIZE;
179         sc->disk->d_name = "sscdisk";
180         sc->disk->d_sectorsize = DEV_BSIZE;
181         sc->disk->d_strategy = sscstrategy;
182         sc->disk->d_unit = sc->unit;
183         sc->disk->d_flags = DISKFLAG_NEEDSGIANT;
184         disk_create(sc->disk, DISK_VERSION);
185         sc->fd = fd;
186         if (sc->unit == 0) 
187                 rootdevnames[0] = "ufs:/dev/sscdisk0";
188         return (sc);
189 }
190
191 static void
192 ssc_drvinit(void *unused)
193 {
194         ssccreate(-1);
195 }
196
197 SYSINIT(sscdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE, ssc_drvinit,NULL);