1 /*        $NetBSD: md_root.c,v 1.36 2023/01/06 10:28:28 tsutsui Exp $ */
2 
3 /*
4  * Copyright (c) 1996 Leo Weppelman.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: md_root.c,v 1.36 2023/01/06 10:28:28 tsutsui Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/kmem.h>
35 #include <sys/buf.h>
36 #include <sys/proc.h>
37 #include <sys/device.h>
38 #include <sys/ioctl.h>
39 #include <sys/fcntl.h>
40 #include <sys/conf.h>
41 #include <sys/disklabel.h>
42 #include <sys/disk.h>
43 #include <sys/dkbad.h>
44 
45 #include <dev/cons.h>
46 #include <dev/md.h>
47 
48 #include <atari/atari/device.h>
49 
50 /*
51  * Misc. defines:
52  */
53 #define   RAMD_CHUNK          (9 * 512) /* Chunk-size for auto-load   */
54 #define   RAMD_NDEV 3                   /* Number of devices configured         */
55 
56 struct   ramd_info {
57           u_long    ramd_size;  /* Size of disk in bytes                        */
58           u_long    ramd_flag;  /* see defs below                               */
59           dev_t     ramd_dev;   /* device to load from                          */
60 };
61 
62 /*
63  * ramd_flag:
64  */
65 #define   RAMD_LOAD 0x01      /* Auto load when first opened          */
66 #define   RAMD_LCOMP          0x02      /* Input is compressed                  */
67 
68 struct ramd_info rd_info[RAMD_NDEV] = {
69     {
70           1105920,            /*        1Mb in 2160 sectors           */
71           RAMD_LOAD,                    /* auto-load this device                */
72           MAKEDISKDEV(2, 0, 2),         /* XXX: This is crap! (720Kb flop)      */
73     },
74     {
75           1474560,            /* 1.44Mb in 2880 sectors               */
76           RAMD_LOAD,                    /* auto-load this device                */
77           MAKEDISKDEV(2, 0, 2),         /* XXX: This is crap! (720Kb flop)      */
78     },
79     {
80           1474560,            /* 1.44Mb in 2880 sectors               */
81           RAMD_LOAD,                    /* auto-load this device                */
82           MAKEDISKDEV(2, 0, 3),         /* XXX: This is crap! (1.44Mb flop)     */
83     }
84 };
85 
86 struct read_info {
87     struct buf      *bp;                /* buffer for strategy function                   */
88     long  nbytes;             /* total number of bytes to read        */
89     long  offset;             /* offset in input medium               */
90     char  *bufp;              /* current output buffer                */
91     char  *ebufp;             /* absolute maximum for bufp            */
92     int             chunk;              /* chunk size on input medium           */
93     int             media_sz; /* size of input medium                           */
94     void  (*strat)(struct buf *);       /* strategy function for read */
95 };
96 
97 
98 static int  loaddisk(struct  md_conf *, dev_t ld_dev, struct lwp *);
99 static int  ramd_norm_read(struct read_info *);
100 
101 #ifdef support_compression
102 static int  cpy_uncompressed(void *, int, struct read_info *);
103 static int  md_compressed(void *, int, struct read_info *);
104 #endif
105 
106 /*
107  * This is called during autoconfig.
108  */
109 void
md_attach_hook(int unit,struct md_conf * md)110 md_attach_hook(int unit, struct md_conf *md)
111 {
112 
113           if (atari_realconfig && (unit < RAMD_NDEV) && rd_info[unit].ramd_flag) {
114                     printf ("md%d: %sauto-load on open. Size %ld bytes.\n", unit,
115                         rd_info[unit].ramd_flag & RAMD_LCOMP ? "decompress/" : "",
116                         rd_info[unit].ramd_size);
117                     md->md_type = MD_UNCONFIGURED; /* Paranoia... */
118           }
119 }
120 
121 void
md_open_hook(int unit,struct md_conf * md)122 md_open_hook(int unit, struct md_conf *md)
123 {
124           struct ramd_info *ri;
125 
126           if (unit >= RAMD_NDEV)
127                     return;
128 
129           ri = &rd_info[unit];
130           if (md->md_type != MD_UNCONFIGURED)
131                     return;   /* Only configure once */
132           md->md_addr = kmem_alloc(ri->ramd_size, KM_SLEEP);
133           md->md_size = ri->ramd_size;
134           if (md->md_addr == NULL)
135                     return;
136           if (ri->ramd_flag & RAMD_LOAD) {
137                     if (loaddisk(md, ri->ramd_dev, curlwp)) {
138                               kmem_free(md->md_addr, ri->ramd_size);
139                               md->md_addr = NULL;
140                               return;
141                     }
142           }
143           md->md_type = MD_KMEM_ALLOCATED;
144 }
145 
146 static int
loaddisk(struct md_conf * md,dev_t ld_dev,struct lwp * lwp)147 loaddisk(struct md_conf *md, dev_t ld_dev, struct lwp *lwp)
148 {
149           struct buf                    *buf;
150           int                           error;
151           const struct bdevsw *bdp;
152           struct disklabel    dl;
153           struct read_info    rs;
154 
155           bdp = bdevsw_lookup(ld_dev);
156           if (bdp == NULL)
157                     return ENXIO;
158 
159           /*
160            * Initialize our buffer header:
161            */
162           buf = getiobuf(NULL, false);
163           buf->b_cflags = BC_BUSY;
164           buf->b_dev   = ld_dev;
165           buf->b_error = 0;
166           buf->b_proc  = lwp->l_proc;
167 
168           /*
169            * Setup read_info:
170            */
171           rs.bp       = buf;
172           rs.nbytes   = md->md_size;
173           rs.offset   = 0;
174           rs.bufp     = md->md_addr;
175           rs.ebufp    = (char *)md->md_addr + md->md_size;
176           rs.chunk    = RAMD_CHUNK;
177           rs.media_sz = md->md_size;
178           rs.strat    = bdp->d_strategy;
179 
180           /*
181            * Open device and try to get some statistics.
182            */
183           if ((error = bdp->d_open(ld_dev, FREAD | FNONBLOCK, 0, lwp)) != 0) {
184                     putiobuf(buf);
185                     return error;
186           }
187           if (bdp->d_ioctl(ld_dev, DIOCGDINFO, (void *)&dl, FREAD, lwp) == 0) {
188                     /* Read on a cylinder basis */
189                     rs.chunk    = dl.d_secsize * dl.d_secpercyl;
190                     rs.media_sz = dl.d_secperunit * dl.d_secsize;
191           }
192 
193 #ifdef support_compression
194           if (ri->ramd_flag & RAMD_LCOMP)
195                     error = decompress(cpy_uncompressed, md_compressed, &rs);
196           else
197 #endif /* support_compression */
198                     error = ramd_norm_read(&rs);
199 
200           bdp->d_close(ld_dev, FREAD | FNONBLOCK, 0, lwp);
201           putiobuf(buf);
202           return error;
203 }
204 
205 static int
ramd_norm_read(struct read_info * rsp)206 ramd_norm_read(struct read_info *rsp)
207 {
208           long                bytes_left;
209           int                 done, error;
210           struct buf          *bp;
211           int                 dotc = 0;
212 
213           bytes_left = rsp->nbytes;
214           bp         = rsp->bp;
215           error      = 0;
216 
217           while (bytes_left > 0) {
218                     bp->b_cflags = BC_BUSY;
219                     bp->b_flags  = B_PHYS | B_READ;
220                     bp->b_oflags &= ~BO_DONE;
221                     bp->b_blkno  = btodb(rsp->offset);
222                     bp->b_bcount = uimin(rsp->chunk, bytes_left);
223                     bp->b_data   = rsp->bufp;
224                     bp->b_error  = 0;
225 
226                     /* Initiate read */
227                     (*rsp->strat)(bp);
228 
229                     /* Wait for results */
230                     biowait(bp);
231                     error = bp->b_error;
232 
233                     /* Dot counter */
234                     printf(".");
235                     if (!(++dotc % 40))
236                               printf("\n");
237 
238                     done = bp->b_bcount - bp->b_resid;
239 
240                     bytes_left   -= done;
241                     rsp->offset  += done;
242                     rsp->bufp    += done;
243 
244                     if (error || !done)
245                               break;
246 
247                     if ((rsp->offset == rsp->media_sz) && (bytes_left != 0)) {
248                               printf("\nInsert next media and hit any key...");
249                               cngetc();
250                               printf("\n");
251                               rsp->offset = 0;
252                     }
253           }
254           printf("\n");
255           return error;
256 }
257 
258 #ifdef support_compression
259 /*
260  * Functions supporting uncompression:
261  */
262 /*
263  * Copy from the uncompression buffer to the ramdisk
264  */
265 static int
cpy_uncompressed(void * buf,int nbyte,struct read_info * rsp)266 cpy_uncompressed(void * buf, int nbyte, struct read_info *rsp)
267 {
268 
269           if ((rsp->bufp + nbyte) >= rsp->ebufp)
270                     return 0;
271           memcpy(rsp->bufp, buf, nbyte);
272           rsp->bufp += nbyte;
273           return 0;
274 }
275 
276 /*
277  * Read a maximum of 'nbyte' bytes into 'buf'.
278  */
279 static int
md_compressed(void * buf,int nbyte,struct read_info * rsp)280 md_compressed(void * buf, int nbyte, struct read_info *rsp)
281 {
282           static int          dotc = 0;
283           struct buf          *bp;
284           int                 nread = 0;
285           int                 done, error;
286 
287 
288           error  = 0;
289           bp     = rsp->bp;
290           nbyte &= ~(DEV_BSIZE - 1);
291 
292           while (nbyte > 0) {
293                     bp->b_cflags = BC_BUSY;
294                     bp->b_flags  = B_PHYS | B_READ;
295                     bp->b_oflags &= ~BO_DONE;
296                     bp->b_blkno  = btodb(rsp->offset);
297                     bp->b_bcount = uimin(rsp->chunk, nbyte);
298                     bp->b_data   = buf;
299                     bp->b_error  = 0;
300 
301                     /* Initiate read */
302                     (*rsp->strat)(bp);
303 
304                     /* Wait for results */
305                     biowait(bp);
306                     error = bp->b_error;
307 
308                     /* Dot counter */
309                     printf(".");
310                     if (!(++dotc % 40))
311                               printf("\n");
312 
313                     done = bp->b_bcount - bp->b_resid;
314 
315                     nbyte        -= done;
316                     nread        += done;
317                     rsp->offset  += done;
318 
319                     if (error || !done)
320                               break;
321 
322                     if ((rsp->offset == rsp->media_sz) && (nbyte != 0)) {
323                               printf("\nInsert next media and hit any key...");
324                               if (cngetc() != '\n')
325                                         printf("\n");
326                               rsp->offset = 0;
327                     }
328           }
329           return nread;
330 }
331 #endif /* support_compression */
332