Core integer types header file reorganization stage 1/2: Create and/or modify
[dragonfly.git] / sys / boot / alpha / libalpha / srmdisk.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/alpha/libalpha/srmdisk.c,v 1.8.2.2 2001/08/01 20:52:03 mjacob Exp $
28  * $DragonFly: src/sys/boot/alpha/libalpha/Attic/srmdisk.c,v 1.3 2003/11/09 02:22:29 dillon Exp $
29  */
30
31 /*
32  * SRM 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 #include <machine/prom.h>
48
49 #include "bootstrap.h"
50 #include "libalpha.h"
51
52 #define SRMDISK_SECSIZE 512
53
54 #define BUFSIZE         (1 * SRMDISK_SECSIZE)
55 #define MAXBDDEV        MAXDEV
56
57 #ifdef DISK_DEBUG
58 # define D(x)   x
59 #else
60 # define D(x)
61 #endif
62
63 static int      bd_init(void);
64 static int      bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
65 static int      bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize);
66 static int      bd_open(struct open_file *f, ...);
67 static int      bd_close(struct open_file *f);
68 static void     bd_print(int verbose);
69
70 struct open_disk {
71     int                 od_fd;
72     int                 od_unit;                /* our unit number */
73     int                 od_boff;                /* block offset from beginning of SRM disk */
74     int                 od_flags;
75 #define BD_FLOPPY       (1<<2)
76     u_char              od_buf[BUFSIZE];        /* transfer buffer (do we want/need this?) */
77 };
78
79 struct devsw srmdisk = {
80     "disk", 
81     DEVT_DISK, 
82     bd_init,
83     bd_strategy, 
84     bd_open, 
85     bd_close, 
86     noioctl,
87     bd_print
88 };
89
90 /*
91  * List of SRM devices, translation from disk unit number to
92  * SRM unit number.
93  */
94 static struct 
95 {
96     char        bd_name[64];
97     int         bd_unit;                /* SRM unit number */
98     int         bd_namelen;
99     int         bd_flags;
100     int         bd_fd;
101     int         bd_opencount;
102 } bdinfo [MAXBDDEV];
103 static int nbdinfo = 0;
104
105 /*    
106  * Quiz SRM for disk devices, save a little info about them.
107  */
108 static int
109 bd_init(void) 
110 {
111     prom_return_t ret;
112     char devname[64];
113
114     bdinfo[0].bd_unit = 0;      /* XXX */
115     bdinfo[0].bd_flags = 0;     /* XXX */
116     ret.bits = prom_getenv(PROM_E_BOOTED_DEV,
117                            bdinfo[0].bd_name, sizeof(bdinfo[0].bd_name));
118     bdinfo[0].bd_namelen = ret.u.retval;
119     bdinfo[0].bd_fd = -1;
120     bdinfo[0].bd_opencount = 0;
121     nbdinfo++;
122
123     return (0);
124 }
125
126 /*
127  * Print information about disks
128  */
129 static void
130 bd_print(int verbose)
131 {
132     int         i;
133     char        line[80];
134     
135     for (i = 0; i < nbdinfo; i++) {
136         sprintf(line, "    disk%d:   SRM drive %s", i, bdinfo[i].bd_name);
137         pager_output(line);
138         /* XXX more detail? */
139         pager_output("\n");
140     }
141 }
142
143 /*
144  * Attempt to open the disk described by (dev) for use by (f).
145  *
146  * Note that the philosophy here is "give them exactly what
147  * they ask for".  This is necessary because being too "smart"
148  * about what the user might want leads to complications.
149  * (eg. given no slice or partition value, with a disk that is
150  *  sliced - are they after the first BSD slice, or the DOS
151  *  slice before it?)
152  */
153 static int 
154 bd_open(struct open_file *f, ...)
155 {
156     __va_list                   args;
157     struct alpha_devdesc        *dev;
158     struct dos_partition        *dptr;
159     struct open_disk            *od;
160     struct disklabel            *lp;
161     int                         sector, slice, i;
162     int                         error;
163     int                         unit, fd;
164     prom_return_t               ret;
165
166     __va_start(args, f);
167     dev = __va_arg(args, struct alpha_devdesc*);
168     __va_end(args);
169
170     unit = dev->d_kind.srmdisk.unit;
171     if (unit >= nbdinfo) {
172         D(printf("attempt to open nonexistent disk\n"));
173         return(ENXIO);
174     }
175     
176     /* Call the prom to open the disk. */
177     if (bdinfo[unit].bd_fd < 0) {
178         ret.bits = prom_open(bdinfo[unit].bd_name, bdinfo[unit].bd_namelen);
179         if (ret.u.status == 2)
180             return (ENXIO);
181         if (ret.u.status == 3)
182             return (EIO);
183         bdinfo[unit].bd_fd = fd = ret.u.retval;
184     } else {
185         fd = bdinfo[unit].bd_fd;
186     }
187     bdinfo[unit].bd_opencount++;
188
189     od = (struct open_disk *) malloc(sizeof(struct open_disk));
190     if (!od) {
191         D(printf("srmdiskopen: no memory\n"));
192         return (ENOMEM);
193     }
194
195     /* Look up SRM unit number, intialise open_disk structure */
196     od->od_fd = fd;
197     od->od_unit = dev->d_kind.srmdisk.unit;
198     od->od_flags = bdinfo[od->od_unit].bd_flags;
199     od->od_boff = 0;
200     error = 0;
201
202 #if 0
203     /* Get geometry for this open (removable device may have changed) */
204     if (set_geometry(&od->od_ll)) {
205         D(printf("bd_open: can't get geometry\n"));
206         error = ENXIO;
207         goto out;
208     }
209 #endif
210
211     /*
212      * Following calculations attempt to determine the correct value
213      * for d->od_boff by looking for the slice and partition specified,
214      * or searching for reasonable defaults.
215      */
216
217 #if 0
218     /*
219      * Find the slice in the DOS slice table.
220      */
221     if (readsects(&od->od_ll, 0, 1, od->od_buf, 0)) {
222         D(printf("bd_open: error reading MBR\n"));
223         error = EIO;
224         goto out;
225     }
226
227     /* 
228      * Check the slice table magic.
229      */
230     if ((od->od_buf[0x1fe] != 0xff) || (od->od_buf[0x1ff] != 0xaa)) {
231         /* If a slice number was explicitly supplied, this is an error */
232         if (dev->d_kind.srmdisk.slice > 0) {
233             D(printf("bd_open: no slice table/MBR (no magic)\n"));
234             error = ENOENT;
235             goto out;
236         }
237         sector = 0;
238         goto unsliced;          /* may be a floppy */
239     }
240     dptr = (struct dos_partition *) & od->od_buf[DOSPARTOFF];
241
242     /* 
243      * XXX No support here for 'extended' slices
244      */
245     if (dev->d_kind.srmdisk.slice <= 0) {
246         /*
247          * Search for the first FreeBSD slice; this also works on "unsliced"
248          * disks, as they contain a "historically bogus" MBR.
249          */
250         for (i = 0; i < NDOSPART; i++, dptr++)
251             if (dptr->dp_typ == DOSPTYP_386BSD) {
252                 sector = dptr->dp_start;
253                 break;
254             }
255         /* Did we find something? */
256         if (sector == -1) {
257             error = ENOENT;
258             goto out;
259         }
260     } else {
261         /*
262          * Accept the supplied slice number unequivocally (we may be looking
263          * for a DOS partition) if we can handle it.
264          */
265         if ((dev->d_kind.srmdisk.slice > NDOSPART) || (dev->d_kind.srmdisk.slice < 1)) {
266             error = ENOENT;
267             goto out;
268         }
269         dptr += (dev->d_kind.srmdisk.slice - 1);
270         sector = dptr->dp_start;
271     }
272  unsliced:
273
274 #else
275     sector = 0;
276 #endif
277     /* 
278      * Now we have the slice, look for the partition in the disklabel if we have
279      * a partition to start with.
280      */
281     if (dev->d_kind.srmdisk.partition < 0) {
282         od->od_boff = sector;           /* no partition, must be after the slice */
283     } else {
284         if (bd_strategy(od, F_READ, sector + LABELSECTOR, 512, od->od_buf, 0)) {
285             D(printf("bd_open: error reading disklabel\n"));
286             error = EIO;
287             goto out;
288         }
289         lp = (struct disklabel *) (od->od_buf + LABELOFFSET);
290         if (lp->d_magic != DISKMAGIC) {
291             D(printf("bd_open: no disklabel\n"));
292 #if 0
293             error = ENOENT;
294             goto out;
295 #endif
296         } else if (dev->d_kind.srmdisk.partition >= lp->d_npartitions) {
297
298             /*
299              * The partition supplied is out of bounds; this is fatal.
300              */
301             D(printf("partition '%c' exceeds partitions in table (a-'%c')\n",
302                      'a' + dev->d_kind.srmdisk.partition, 'a' + lp->d_npartitions));
303             error = EPART;
304             goto out;
305
306         } else {
307
308             /*
309              * Complain if the partition type is wrong and it shouldn't be, but
310              * regardless accept this partition.
311              */
312             D(if ((lp->d_partitions[dev->d_kind.srmdisk.partition].p_fstype == FS_UNUSED) &&
313                   !(od->od_flags & BD_FLOPPY))      /* Floppies often have bogus fstype */
314               printf("bd_open: warning, partition marked as unused\n"););
315
316             od->od_boff = lp->d_partitions[dev->d_kind.srmdisk.partition].p_offset;
317         }
318     }
319     /*
320      * Save our context
321      */
322     f->f_devdata = od;
323
324  out:
325     if (error)
326         free(od);
327     return(error);
328 }
329
330 static int 
331 bd_close(struct open_file *f)
332 {
333     struct open_disk    *od = f->f_devdata;
334
335     bdinfo[od->od_unit].bd_opencount--;
336     if (bdinfo[od->od_unit].bd_opencount == 0) {
337         (void)prom_close(od->od_fd);
338         bdinfo[od->od_unit].bd_fd = -1;
339     }
340
341     free(od);
342     f->f_devdata = NULL;
343     return(0);
344 }
345
346 static int 
347 bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize)
348 {
349     struct bcache_devdata       bcd;
350     struct open_disk    *od = (struct open_disk *)devdata;
351     
352     bcd.dv_strategy = bd_realstrategy;
353     bcd.dv_devdata = devdata;
354     return(bcache_strategy(&bcd, od->od_unit, rw, dblk + od->od_boff, size, buf, rsize));
355 }
356
357 static int 
358 bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize)
359 {
360     prom_return_t       ret;
361     struct open_disk    *od = (struct open_disk *)devdata;
362
363     if (size % SRMDISK_SECSIZE)
364         panic("bd_strategy: I/O not block multiple");
365
366     if (flag != F_READ)
367         return(EROFS);
368
369     if (rsize)
370         *rsize = 0;
371
372     ret.bits = prom_read(od->od_fd, size, buf, dblk);
373     if (ret.u.status) {
374         D(printf("read error\n"));
375         return (EIO);
376     }
377
378     if (rsize)
379         *rsize = size;
380     return (0);
381 }
382