1 /*        $NetBSD: disk.c,v 1.12 2016/02/14 18:09:51 dholland Exp $   */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Van Jacobson of Lawrence Berkeley Laboratory and Ralph Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *        @(#)disk.c          8.1 (Berkeley) 6/10/93
35  */
36 
37 #include <lib/libsa/stand.h>
38 
39 #include <sys/param.h>
40 #include <sys/disklabel.h>
41 
42 #include <dev/arcbios/arcbios.h>
43 
44 #include "common.h"
45 #include "disk.h"
46 
47 #define   RF_PROTECTED_SECTORS          64        /* XXX refer to <.../rf_optnames.h> */
48 
49 struct    disk_softc {
50           u_long    sc_fd;                        /* ARCBIOS file id */
51           int       sc_part;            /* disk partition number */
52           struct    disklabel sc_label; /* disk label for this disk */
53 };
54 
55 int
diskstrategy(void * devdata,int rw,daddr_t bn,size_t reqcnt,void * addr,size_t * cnt)56 diskstrategy(void *devdata, int rw, daddr_t bn, size_t reqcnt, void *addr,
57     size_t *cnt)
58 {
59           struct disk_softc *sc = (struct disk_softc *)devdata;
60           int part = sc->sc_part;
61           struct partition *pp = &sc->sc_label.d_partitions[part];
62           long error;
63           int64_t offset;
64           u_long count;
65 
66           offset = bn;
67 
68           /*
69            * Partial-block transfers not handled.
70            */
71           if (reqcnt & (DEV_BSIZE - 1)) {
72                     *cnt = 0;
73                     return EINVAL;
74           }
75 
76           offset += pp->p_offset;
77 
78           if (pp->p_fstype == FS_RAID)
79                     offset += RF_PROTECTED_SECTORS;
80 
81           /*
82            * Convert from blocks to bytes.
83            */
84           offset *= DEV_BSIZE;
85 
86           error = arcbios_Seek(sc->sc_fd, &offset, 0);
87           if (error != ARCBIOS_ESUCCESS)
88                     return EIO;
89           error = arcbios_Read(sc->sc_fd, addr, reqcnt, &count);
90           if (error != ARCBIOS_ESUCCESS)
91                     return EIO;
92 
93           *cnt = count;
94           return 0;
95 }
96 
97 int
diskopen(struct open_file * f,...)98 diskopen(struct open_file *f, ...)
99 {
100           int part;
101 
102           struct disk_softc *sc;
103           struct disklabel *lp;
104 #ifdef arc
105           char *msg, buf[DEV_BSIZE];
106           size_t cnt;
107           int mbrp_off, i;
108 #endif
109           int error;
110           u_long fd;
111           char *device;
112           va_list ap;
113 
114           va_start(ap, f);
115           device = va_arg(ap, char *);
116           va_end(ap);
117 
118           /*
119            * For NetBSD/sgimips, since we use the SGI partition map directly,
120            * we fake an in-core NetBSD disklabel with offset of 0.
121            *
122            * For NetBSD/arc, there is a MBR partition map on the disk, which we
123            * then expect to find a NetBSD disklabel within the MBR partition.
124            * We require that the kernel be located in first partition in the
125            * NetBSD disklabel, because we have not other way to represent the
126            * root partition.
127            */
128           part = 0;
129 
130           if (part >= MAXPARTITIONS)
131                     return ENXIO;
132 
133           error = arcbios_Open(device, 0, &fd);
134           if (error) {
135                     printf("diskopen: open failed, errno = %d\n", error);
136                     return ENXIO;
137           }
138 
139           sc = alloc(sizeof(struct disk_softc));
140           memset(sc, 0, sizeof(struct disk_softc));
141           f->f_devdata = (void *)sc;
142 
143           sc->sc_fd = fd;
144           sc->sc_part = part;
145 
146           /* try to read disk label and partition table information */
147           lp = &sc->sc_label;
148           lp->d_secsize = DEV_BSIZE;
149           lp->d_secpercyl = 1;
150           lp->d_npartitions = MAXPARTITIONS;
151           lp->d_partitions[part].p_offset = 0;
152           lp->d_partitions[part].p_size = 0x7fffffff;
153 
154 #ifdef arc
155           error = diskstrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE,
156               buf, &cnt);
157           if (error || cnt != DEV_BSIZE) {
158                     printf("%s: can't read disklabel, errno = %d\n",
159                         device, error);
160                     dealloc(sc, sizeof(struct disk_softc));
161                     return ENXIO;
162           }
163           msg = getdisklabel(buf, lp);
164           if (msg) {
165                     /* If no label, just assume 0 and return */
166                     return 0;
167           }
168 
169           /*
170            * On arc, we can't open whole disk, but can open each partition with
171            * OSLOADPARTITION like scsi(0)disk(0)rdisk()partition(1) etc.
172            * Thus, we don't have to add offset of the MBR partition.
173            */
174           /* XXX magic: partition 2 is whole NetBSD partition */
175           mbrp_off = lp->d_partitions[2].p_offset;
176           for (i = 0; i < MAXPARTITIONS; i++) {
177                     if (lp->d_partitions[i].p_fstype != FS_UNUSED &&
178                         lp->d_partitions[i].p_offset >= mbrp_off)
179                               lp->d_partitions[i].p_offset -= mbrp_off;
180           }
181 
182           if (part >= lp->d_npartitions ||
183               lp->d_partitions[part].p_fstype == FS_UNUSED ||
184               lp->d_partitions[part].p_size == 0) {
185                     dealloc(sc, sizeof(struct disk_softc));
186                     return ENXIO;
187           }
188 #endif
189           return 0;
190 }
191 
192 #ifndef LIBSA_NO_DEV_CLOSE
193 int
diskclose(struct open_file * f)194 diskclose(struct open_file *f)
195 {
196 
197           arcbios_Close(((struct disk_softc *)(f->f_devdata))->sc_fd);
198           dealloc(f->f_devdata, sizeof(struct disk_softc));
199           f->f_devdata = NULL;
200           return 0;
201 }
202 #endif
203