Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / boot / arc / lib / arcdisk.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 1998 Doug Rabson <dfr@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/boot/arc/lib/arcdisk.c,v 1.3.2.1 2001/01/05 17:37:51 mjacob Exp $
28  * $DragonFly: src/sys/boot/arc/lib/Attic/arcdisk.c,v 1.2 2003/06/17 04:28:16 dillon Exp $
29  */
30
31 /*
32  * ARC disk device handling.
33  * 
34  * Ideas and algorithms from:
35  *
36  * - NetBSD libi386/biosdisk.c
37  * - FreeBSD biosboot/disk.c
38  *
39  */
40
41 #include <stand.h>
42
43 #include <sys/disklabel.h>
44 #include <sys/diskslice.h>
45
46 #include <machine/stdarg.h>
47
48 #include "bootstrap.h"
49 #include "libarc.h"
50 #include "arctypes.h"
51 #include "arcfuncs.h"
52
53 #define ARCDISK_SECSIZE 512
54
55 #define BUFSIZE         (1 * ARCDISK_SECSIZE)
56 #define MAXBDDEV        MAXDEV
57
58 #ifdef DISK_DEBUG
59 # define D(x)   x
60 #else
61 # define D(x)
62 #endif
63
64 static int      bd_init(void);
65 static int      bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize);
66 static int      bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize);
67 static int      bd_open(struct open_file *f, ...);
68 static int      bd_close(struct open_file *f);
69 static void     bd_print(int verbose);
70
71 struct open_disk {
72     int                 od_fd;
73     int                 od_unit;                /* our unit number */
74     int                 od_boff;                /* block offset from beginning of ARC disk */
75     int                 od_flags;
76 #define BD_FLOPPY       (1<<2)
77     u_char              od_buf[BUFSIZE];        /* transfer buffer (do we want/need this?) */
78 };
79
80 struct devsw arcdisk = {
81     "disk", 
82     DEVT_DISK, 
83     bd_init,
84     bd_strategy, 
85     bd_open, 
86     bd_close, 
87     noioctl,
88     bd_print
89 };
90
91 /*
92  * List of ARC devices, translation from disk unit number to
93  * ARC unit number.
94  */
95 static struct 
96 {
97     char        bd_name[64];
98     int         bd_unit;                /* ARC unit number */
99     int         bd_namelen;
100     int         bd_flags;
101 } bdinfo [MAXBDDEV];
102 static int nbdinfo = 0;
103
104 /*    
105  * Quiz ARC for disk devices, save a little info about them.
106  */
107 static int
108 bd_init(void) 
109 {
110     nbdinfo++;
111
112     return (0);
113 }
114
115 /*
116  * Print information about disks
117  */
118 static void
119 bd_print(int verbose)
120 {
121     int         i;
122     char        line[80];
123     
124     for (i = 0; i < nbdinfo; i++) {
125         sprintf(line, "    disk%d:   ARC drive %s", i, bdinfo[i].bd_name);
126         pager_output(line);
127         /* XXX more detail? */
128         pager_output("\n");
129     }
130 }
131
132 /*
133  * Attempt to open the disk described by (dev) for use by (f).
134  *
135  * Note that the philosophy here is "give them exactly what
136  * they ask for".  This is necessary because being too "smart"
137  * about what the user might want leads to complications.
138  * (eg. given no slice or partition value, with a disk that is
139  *  sliced - are they after the first BSD slice, or the DOS
140  *  slice before it?)
141  */
142 static int 
143 bd_open(struct open_file *f, ...)
144 {
145     struct arc_devdesc          *dev;
146     struct dos_partition        *dptr;
147     struct open_disk            *od;
148     struct disklabel            *lp;
149     int                         sector, slice, i;
150     int                         error;
151     int                         unit;
152     u_int32_t                   fd;
153     va_list                     ap;
154
155     va_start(ap, f);
156     dev = va_arg(ap, struct arc_devdesc *);
157     va_end(ap);
158
159     unit = dev->d_kind.arcdisk.unit;
160     if (unit >= nbdinfo) {
161         D(printf("attempt to open nonexistent disk\n"));
162         return(ENXIO);
163     }
164     
165     if (Open("scsi(0)disk(0)rdisk(0)partition(0)",
166              OpenReadOnly, &fd) != ESUCCESS)
167       if (Open("scsi(0)disk(1)rdisk(0)partition(0)",
168                OpenReadOnly, &fd) != ESUCCESS)
169         if (Open("multi(0)disk(0)fdisk(0)partition(0)",
170                  OpenReadOnly, &fd) != ESUCCESS)
171         return(ENXIO);
172
173     od = (struct open_disk *) malloc(sizeof(struct open_disk));
174     if (!od) {
175         D(printf("arcdiskopen: no memory\n"));
176         return (ENOMEM);
177     }
178
179     /* Look up ARC unit number, intialise open_disk structure */
180     od->od_fd = fd;
181     od->od_unit = dev->d_kind.arcdisk.unit;
182     od->od_flags = bdinfo[od->od_unit].bd_flags;
183     od->od_boff = 0;
184     error = 0;
185
186 #if 0
187     /* Get geometry for this open (removable device may have changed) */
188     if (set_geometry(&od->od_ll)) {
189         D(printf("bd_open: can't get geometry\n"));
190         error = ENXIO;
191         goto out;
192     }
193 #endif
194
195     /*
196      * Following calculations attempt to determine the correct value
197      * for d->od_boff by looking for the slice and partition specified,
198      * or searching for reasonable defaults.
199      */
200
201 #if 0
202     /*
203      * Find the slice in the DOS slice table.
204      */
205     if (readsects(&od->od_ll, 0, 1, od->od_buf, 0)) {
206         D(printf("bd_open: error reading MBR\n"));
207         error = EIO;
208         goto out;
209     }
210
211     /* 
212      * Check the slice table magic.
213      */
214     if ((od->od_buf[0x1fe] != 0xff) || (od->od_buf[0x1ff] != 0xaa)) {
215         /* If a slice number was explicitly supplied, this is an error */
216         if (dev->d_kind.arcdisk.slice > 0) {
217             D(printf("bd_open: no slice table/MBR (no magic)\n"));
218             error = ENOENT;
219             goto out;
220         }
221         sector = 0;
222         goto unsliced;          /* may be a floppy */
223     }
224     dptr = (struct dos_partition *) & od->od_buf[DOSPARTOFF];
225
226     /* 
227      * XXX No support here for 'extended' slices
228      */
229     if (dev->d_kind.arcdisk.slice <= 0) {
230         /*
231          * Search for the first FreeBSD slice; this also works on "unsliced"
232          * disks, as they contain a "historically bogus" MBR.
233          */
234         for (i = 0; i < NDOSPART; i++, dptr++)
235             if (dptr->dp_typ == DOSPTYP_386BSD) {
236                 sector = dptr->dp_start;
237                 break;
238             }
239         /* Did we find something? */
240         if (sector == -1) {
241             error = ENOENT;
242             goto out;
243         }
244     } else {
245         /*
246          * Accept the supplied slice number unequivocally (we may be looking
247          * for a DOS partition) if we can handle it.
248          */
249         if ((dev->d_kind.arcdisk.slice > NDOSPART) || (dev->d_kind.arcdisk.slice < 1)) {
250             error = ENOENT;
251             goto out;
252         }
253         dptr += (dev->d_kind.arcdisk.slice - 1);
254         sector = dptr->dp_start;
255     }
256  unsliced:
257
258 #else
259     sector = 0;
260 #endif
261     /* 
262      * Now we have the slice, look for the partition in the disklabel if we have
263      * a partition to start with.
264      */
265     if (dev->d_kind.arcdisk.partition < 0) {
266         od->od_boff = sector;           /* no partition, must be after the slice */
267     } else {
268         if (bd_strategy(od, F_READ, sector + LABELSECTOR, 512, od->od_buf, 0)) {
269             D(printf("bd_open: error reading disklabel\n"));
270             error = EIO;
271             goto out;
272         }
273         lp = (struct disklabel *) (od->od_buf + LABELOFFSET);
274         if (lp->d_magic != DISKMAGIC) {
275             D(printf("bd_open: no disklabel\n"));
276             error = ENOENT;
277             goto out;
278
279         } else if (dev->d_kind.arcdisk.partition >= lp->d_npartitions) {
280
281             /*
282              * The partition supplied is out of bounds; this is fatal.
283              */
284             D(printf("partition '%c' exceeds partitions in table (a-'%c')\n",
285                      'a' + dev->d_kind.arcdisk.partition, 'a' + lp->d_npartitions));
286             error = EPART;
287             goto out;
288
289         } else {
290
291             /*
292              * Complain if the partition type is wrong and it shouldn't be, but
293              * regardless accept this partition.
294              */
295             D(if ((lp->d_partitions[dev->d_kind.arcdisk.partition].p_fstype == FS_UNUSED) &&
296                   !(od->od_flags & BD_FLOPPY))      /* Floppies often have bogus fstype */
297               printf("bd_open: warning, partition marked as unused\n"););
298
299             od->od_boff = lp->d_partitions[dev->d_kind.arcdisk.partition].p_offset;
300         }
301     }
302     /*
303      * Save our context
304      */
305     f->f_devdata = od;
306
307  out:
308     if (error)
309         free(od);
310     return(error);
311 }
312
313 static int 
314 bd_close(struct open_file *f)
315 {
316     struct open_disk    *od = f->f_devdata;
317
318     Close(od->od_fd);
319
320     free(od);
321     f->f_devdata = NULL;
322     return(0);
323 }
324
325 static int 
326 bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize)
327 {
328     struct bcache_devdata       bcd;
329     struct arc_devdesc  *dev = (struct arc_devdesc *)devdata;
330     
331     bcd.dv_strategy = bd_realstrategy;
332     bcd.dv_devdata = devdata;
333     return(bcache_strategy(&bcd, dev->d_kind.arcdisk.unit, rw, dblk, size,
334                            buf, rsize));
335 }
336
337 static int 
338 bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, char *buf, size_t *rsize)
339 {
340     struct open_disk    *od = (struct open_disk *)devdata;
341     fpos_t              seek;
342     u_int32_t           count;
343
344     if (size % ARCDISK_SECSIZE)
345         panic("bd_strategy: I/O not block multiple");
346
347     if (flag != F_READ)
348         return(EROFS);
349
350     if (rsize)
351         *rsize = 0;
352
353     seek = 512 * (dblk + od->od_boff);
354     Seek(od->od_fd, &seek, SeekAbsolute);
355     if (Read(od->od_fd, buf, size, &count) != ESUCCESS) {
356         D(printf("read error\n"));
357         return (EIO);
358     }
359
360     if (rsize)
361         *rsize = count;
362     return (0);
363 }
364