Merge from vendor branch LESS:
[dragonfly.git] / sys / contrib / dev / fla / fla.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: src/sys/contrib/dev/fla/fla.c,v 1.16 1999/12/08 04:45:16 ken Exp $ 
10  * $DragonFly: src/sys/contrib/dev/fla/Attic/fla.c,v 1.18 2007/05/15 00:01:03 dillon Exp $ 
11  *
12  */
13
14 #include "use_fla.h"
15
16 #include <sys/param.h>
17 #include <sys/systm.h>
18 #include <sys/sysctl.h>
19 #include <sys/kernel.h>
20 #include <sys/proc.h>
21 #include <sys/buf.h>
22 #include <sys/malloc.h>
23 #include <sys/conf.h>
24 #include <sys/disk.h>
25 #include <sys/devicestat.h>
26 #include <sys/module.h>
27 #include <machine/clock.h>
28
29 #include <vm/vm.h>
30 #include <vm/pmap.h>
31 #include <vm/vm_param.h>
32 #include <sys/buf2.h>
33 #include <sys/thread2.h>
34
35 #include <sys/bus.h>
36 #include <bus/isa/isavar.h>
37
38 #ifdef SMP
39 #include <machine/smp.h>
40 #define LEAVE() rel_mplock();                   
41 #define ENTER() get_mplock();                   
42 #else
43 #define LEAVE()
44 #define ENTER()
45 #endif
46
47 #include <contrib/dev/fla/msysosak.h>
48
49 MALLOC_DEFINE(M_FLA, "fla driver", "fla driver storage");
50
51 static int fla_debug = 0;
52 SYSCTL_INT(_debug, OID_AUTO, fladebug, CTLFLAG_RW, &fla_debug, 0, "");
53
54 #define CDEV_MAJOR      102
55 #define BDEV_MAJOR      28
56
57 static d_strategy_t flastrategy;
58 static d_open_t flaopen;
59 static d_close_t flaclose;
60 static d_ioctl_t flaioctl;
61
62 static struct dev_ops fla_ops = {
63         { "fla", CDEV_MAJOR, D_DISK | D_CANFREE },
64         .d_open =       flaopen,
65         .d_close =      flaclose,
66         .d_read =       physread,
67         .d_write =      physwrite,
68         .d_ioctl =      flaioctl,
69         .d_strategy =   flastrategy,
70 };
71
72 void *
73 doc2k_malloc(int bytes) 
74 {
75         return kmalloc(bytes, M_FLA, M_WAITOK);
76 }
77
78 void
79 doc2k_free(void *ptr)
80 {
81         kfree(ptr, M_FLA);
82 }
83
84 void
85 doc2k_delay(unsigned msec)
86 {
87         DELAY(1000 * msec);
88 }
89
90 void
91 doc2k_memcpy(void *dst, const void *src, unsigned len)
92 {
93         bcopy(src, dst, len);
94 }
95
96 int
97 doc2k_memcmp(const void *dst, const void *src, unsigned len)
98 {
99         return (bcmp(src, dst, len));
100 }
101
102 void
103 doc2k_memset(void *dst, int c, unsigned len)
104 {
105         u_char *p = dst;
106         while (len--)
107                 *p++ = c;
108 }
109
110 static struct fla_s {
111         int busy;
112         int unit;
113         unsigned nsect;
114         struct doc2k_stat ds;
115         struct bio_queue_head bio_queue;
116         struct devstat stats;
117         struct disk disk;
118         cdev_t dev;
119 } softc[NFLA];
120
121 static int
122 flaopen(struct dev_open_args *ap)
123 {
124         cdev_t dev = ap->a_head.a_dev;
125         struct fla_s *sc;
126         int error;
127         struct disk_info info;
128         u_int secperunit = 0;
129         u_int secpertrack = 0;
130         u_int ncylinders = 0;
131         u_int nheads = 0;
132
133         if (fla_debug)
134                 kprintf("flaopen(%s %x %x)\n",
135                         devtoname(dev), ap->a_oflags, ap->a_devtype);
136
137         sc = dev->si_drv1;
138
139         error = doc2k_open(sc->unit);
140
141         if (error) {
142                 kprintf("doc2k_open(%d) -> err %d\n", sc->unit, error);
143                 return (EIO);
144         }
145
146         bzero(&info, sizeof(info));
147         error = doc2k_size(sc->unit, &secperunit, &ncylinders,
148                            &nheads, &secpertrack);
149         info.d_media_blksize = DEV_BSIZE;
150         if (error == 0) {
151                 info.d_media_blocks = secperunit;
152                 info.d_media_size = 0;
153                 info.d_nheads = nheads;
154                 info.d_ncylinders = ncylinders;
155                 info.d_secpertrack = secpertrack;
156                 info.d_secpercyl = nheads * secpertrack; /* XXX */
157         }
158         disk_setdiskinfo(&sc->disk, &info);
159         return (0);
160 }
161
162 static int
163 flaclose(struct dev_close_args *ap)
164 {
165         cdev_t dev = ap->a_head.a_dev;
166         int error;
167         struct fla_s *sc;
168
169         if (fla_debug)
170                 kprintf("flaclose(%s %x %x)\n",
171                         devtoname(dev), ap->a_fflag, ap->a_devtype);
172
173         sc = dev->si_drv1;
174
175         error = doc2k_close(sc->unit);
176         if (error) {
177                 kprintf("doc2k_close(%d) -> err %d\n", sc->unit, error);
178                 return (EIO);
179         }
180         return (0);
181 }
182
183 static int
184 flaioctl(struct dev_ioctl_args *ap)
185 {
186         cdev_t dev = ap->a_head.a_dev;
187
188         if (fla_debug)
189                 kprintf("flaioctl(%s %lx %p %x)\n",
190                         devtoname(dev), ap->a_cmd, ap->a_data, ap->a_fflag);
191
192         return (ENOIOCTL);
193 }
194
195 static int
196 flastrategy(struct dev_strategy_args *ap)
197 {
198         cdev_t dev = ap->a_head.a_dev;
199         struct bio *bio = ap->a_bio;
200         struct buf *bp = bio->bio_buf;
201         int unit, error;
202         struct fla_s *sc;
203         enum doc2k_work what;
204
205         if (fla_debug > 1) {
206                 kprintf("flastrategy(%p) %s %x, %lld, %d, %p)\n",
207                         bp, devtoname(dev), bp->b_flags, bio->bio_offset, 
208                         bp->b_bcount, bp->b_data);
209         }
210
211         sc = dev->si_drv1;
212         bio->bio_driver_info = dev;
213         crit_enter();
214         bioqdisksort(&sc->bio_queue, bio);
215         if (sc->busy) {
216                 crit_exit();
217                 return(0);
218         }
219         sc->busy++;
220         
221         while (1) {
222                 bio = bioq_first(&sc->bio_queue);
223                 if (bio == NULL) {
224                         crit_exit();
225                         break;
226                 }
227                 bioq_remove(&sc->bio_queue, bio);
228                 bp = bio->bio_buf;
229                 dev = bio->bio_driver_info;
230
231                 devstat_start_transaction(&sc->stats);
232                 bp->b_resid = bp->b_bcount;
233                 unit = dkunit(dev);
234
235                 switch(bp->b_cmd) {
236                 case BUF_CMD_FREEBLKS:
237                         what = DOC2K_ERASE;
238                         break;
239                 case BUF_CMD_READ:
240                         what = DOC2K_READ;
241                         break;
242                 case BUF_CMD_WRITE:
243                         what = DOC2K_WRITE;
244                         break;
245                 default:
246                         panic("fla: bad b_cmd %d", bp->b_cmd);
247                 }
248
249                 LEAVE();
250
251                 error = doc2k_rwe(unit, what,
252                                   (unsigned)(bio->bio_offset >> DEV_BSHIFT),
253                                   bp->b_bcount / DEV_BSIZE, bp->b_data);
254
255                 ENTER();
256
257                 if (fla_debug > 1 || error) {
258                         kprintf("fla%d: %d = rwe(%p, %d, %d, %lld, %d, %p)\n",
259                             unit, error, bp, unit, what, bio->bio_offset, 
260                             bp->b_bcount, bp->b_data);
261                 }
262                 if (error) {
263                         bp->b_error = EIO;
264                         bp->b_flags |= B_ERROR;
265                 } else {
266                         bp->b_resid = 0;
267                 }
268                 devstat_end_transaction_buf(&sc->stats, bp);
269                 biodone(bio);
270
271                 crit_enter();
272         }
273         sc->busy = 0;
274         return(0);
275 }
276
277 static int
278 flaprobe (device_t dev)
279 {
280         int unit;
281         struct fla_s *sc;
282         int i;
283
284         unit = device_get_unit(dev);
285         sc = &softc[unit];
286
287         /* This is slightly ugly */
288         i = doc2k_probe(unit, KERNBASE + 0xc0000, KERNBASE + 0xe0000);
289         if (i)
290                 return (ENXIO);
291
292         i = doc2k_info(unit, &sc->ds);
293         if (i)
294                 return (ENXIO);
295
296         bus_set_resource(dev, SYS_RES_MEMORY, 0, 
297                 sc->ds.window - KERNBASE, 8192);
298
299         return (0);
300 }
301
302 static int
303 flaattach (device_t dev)
304 {
305         int unit;
306         int i, j, k, l, m, error;
307         struct fla_s *sc;
308
309         unit = device_get_unit(dev);
310         sc = &softc[unit];
311
312         error = doc2k_open(unit);
313         if (error) {
314                 kprintf("doc2k_open(%d) -> err %d\n", unit, error);
315                 return (EIO);
316         }
317
318         error = doc2k_size(unit, &sc->nsect, &i, &j, &k );
319         if (error) {
320                 kprintf("doc2k_size(%d) -> err %d\n", unit, error);
321                 return (EIO);
322         }
323
324         kprintf("fla%d: <%s %s>\n", unit, sc->ds.product, sc->ds.model);
325
326         error = doc2k_close(unit);
327         if (error) {
328                 kprintf("doc2k_close(%d) -> err %d\n", unit, error);
329                 return (EIO);
330         }
331         
332         m = 1024L * 1024L / DEV_BSIZE;
333         l = (sc->nsect * 10 + m/2) / m;
334         kprintf("fla%d: %d.%01dMB (%u sectors),"
335             " %d cyls, %d heads, %d S/T, 512 B/S\n",
336             unit, l / 10, l % 10, sc->nsect, i, j, k);
337
338         if (bootverbose)
339                 kprintf("fla%d: JEDEC=0x%x unitsize=%ld mediasize=%ld"
340                        " chipsize=%ld interleave=%d window=%lx\n", 
341                     unit, sc->ds.type, sc->ds.unitSize, sc->ds.mediaSize, 
342                     sc->ds.chipSize, sc->ds.interleaving, sc->ds.window);
343
344         bioq_init(&sc->bio_queue);
345
346         devstat_add_entry(&softc[unit].stats, "fla", unit, DEV_BSIZE,
347                 DEVSTAT_NO_ORDERED_TAGS, 
348                 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER,
349                 DEVSTAT_PRIORITY_DISK);
350
351         sc->dev = disk_create(unit, &sc->disk, &fla_ops);
352         sc->dev->si_drv1 = sc;
353         sc->unit = unit;
354
355         return (0);
356 }
357
358 static device_method_t fla_methods[] = {
359         /* Device interface */
360         DEVMETHOD(device_probe,         flaprobe),
361         DEVMETHOD(device_attach,        flaattach),
362         {0, 0}
363 };
364
365 static driver_t fladriver = {
366         "fla",
367         fla_methods,
368         sizeof(struct fla_s),
369 };
370
371 static devclass_t       fla_devclass;
372
373 DRIVER_MODULE(fla, isa, fladriver, fla_devclass, 0, 0);