xref: /netbsd/sys/arch/vax/vax/disksubr.c (revision bf9ec67e)
1 /*	$NetBSD: disksubr.c,v 1.30 2002/03/05 09:40:42 simonb Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/buf.h>
41 #include <sys/dkbad.h>
42 #include <sys/disklabel.h>
43 #include <sys/syslog.h>
44 #include <sys/proc.h>
45 #include <sys/user.h>
46 
47 #include <uvm/uvm_extern.h>
48 
49 #include <machine/macros.h>
50 #include <machine/pte.h>
51 #include <machine/pcb.h>
52 #include <machine/cpu.h>
53 
54 #include <dev/mscp/mscp.h> /* For disk encoding scheme */
55 
56 /*
57  * Determine the size of the transfer, and make sure it is
58  * within the boundaries of the partition. Adjust transfer
59  * if needed, and signal errors or early completion.
60  */
61 int
62 bounds_check_with_label(struct buf *bp, struct disklabel *lp, int wlabel)
63 {
64 	struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
65 	int labelsect = lp->d_partitions[2].p_offset;
66 	int maxsz = p->p_size,
67 		sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
68 	/* overwriting disk label ? */
69 	if (bp->b_blkno + p->p_offset <= LABELSECTOR + labelsect &&
70 	    (bp->b_flags & B_READ) == 0 && wlabel == 0) {
71 		bp->b_error = EROFS;
72 		goto bad;
73 	}
74 
75 	/* beyond partition? */
76 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
77 		/* if exactly at end of disk, return an EOF */
78 		if (bp->b_blkno == maxsz) {
79 			bp->b_resid = bp->b_bcount;
80 			return(0);
81 		}
82 		/* or truncate if part of it fits */
83 		sz = maxsz - bp->b_blkno;
84 		if (sz <= 0) {
85 			bp->b_error = EINVAL;
86 			goto bad;
87 		}
88 		bp->b_bcount = sz << DEV_BSHIFT;
89 	}
90 
91 	/* calculate cylinder for disksort to order transfers with */
92 	bp->b_cylinder = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
93 	return(1);
94 
95 bad:
96 	bp->b_flags |= B_ERROR;
97 	return(-1);
98 }
99 
100 /*
101  * Attempt to read a disk label from a device
102  * using the indicated strategy routine.
103  * The label must be partly set up before this:
104  * secpercyl and anything required in the strategy routine
105  * (e.g., sector size) must be filled in before calling us.
106  * Returns null on success and an error string on failure.
107  */
108 char *
109 readdisklabel(dev_t dev, void (*strat)(struct buf *),
110     struct disklabel *lp, struct cpu_disklabel *osdep)
111 {
112 	struct buf *bp;
113 	struct disklabel *dlp;
114 	char *msg = NULL;
115 
116 	if (lp->d_npartitions == 0) { /* Assume no label */
117 		lp->d_secperunit = 0x1fffffff;
118 		lp->d_npartitions = 3;
119 		lp->d_partitions[2].p_size = 0x1fffffff;
120 		lp->d_partitions[2].p_offset = 0;
121 	}
122 
123 	bp = geteblk((int)lp->d_secsize);
124 	bp->b_dev = dev;
125 	bp->b_blkno = LABELSECTOR;
126 	bp->b_bcount = lp->d_secsize;
127 	bp->b_flags |= B_READ;
128 	bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
129 	(*strat)(bp);
130 	if (biowait(bp)) {
131 		msg = "I/O error";
132 	} else {
133 		dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
134 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
135 			msg = "no disk label";
136 		} else if (dlp->d_npartitions > MAXPARTITIONS ||
137 		    dkcksum(dlp) != 0)
138 			msg = "disk label corrupted";
139 		else {
140 			*lp = *dlp;
141 		}
142 	}
143 	brelse(bp);
144 	return (msg);
145 }
146 
147 /*
148  * Check new disk label for sensibility
149  * before setting it.
150  */
151 int
152 setdisklabel(struct disklabel *olp, struct disklabel *nlp,
153     u_long openmask, struct cpu_disklabel *osdep)
154 {
155 	int i;
156 	struct partition *opp, *npp;
157 
158 	if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
159 	    dkcksum(nlp) != 0)
160 		return (EINVAL);
161 	while ((i = ffs(openmask)) != 0) {
162 		i--;
163 		openmask &= ~(1 << i);
164 		if (nlp->d_npartitions <= i)
165 			return (EBUSY);
166 		opp = &olp->d_partitions[i];
167 		npp = &nlp->d_partitions[i];
168 		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
169 			return (EBUSY);
170 		/*
171 		 * Copy internally-set partition information
172 		 * if new label doesn't include it.		XXX
173 		 */
174 		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
175 			npp->p_fstype = opp->p_fstype;
176 			npp->p_fsize = opp->p_fsize;
177 			npp->p_frag = opp->p_frag;
178 			npp->p_cpg = opp->p_cpg;
179 		}
180 	}
181 	nlp->d_checksum = 0;
182 	nlp->d_checksum = dkcksum(nlp);
183 	*olp = *nlp;
184 	return (0);
185 }
186 
187 /*
188  * Write disk label back to device after modification.
189  * Always allow writing of disk label; even if the disk is unlabeled.
190  */
191 int
192 writedisklabel(dev_t dev, void (*strat)(struct buf *),
193     struct disklabel *lp, struct cpu_disklabel *osdep)
194 {
195 	struct buf *bp;
196 	struct disklabel *dlp;
197 	int error = 0;
198 
199 	bp = geteblk((int)lp->d_secsize);
200 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART);
201 	bp->b_blkno = LABELSECTOR;
202 	bp->b_bcount = lp->d_secsize;
203 	bp->b_flags |= B_READ;
204 	(*strat)(bp);
205 	if ((error = biowait(bp)))
206 		goto done;
207 	dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
208 	bcopy(lp, dlp, sizeof(struct disklabel));
209 	bp->b_flags &= ~(B_READ|B_DONE);
210 	bp->b_flags |= B_WRITE;
211 	(*strat)(bp);
212 	error = biowait(bp);
213 
214 done:
215 	brelse(bp);
216 	return (error);
217 }
218 
219 /*
220  * Print out the name of the device; ex. TK50, RA80. DEC uses a common
221  * disk type encoding scheme for most of its disks.
222  */
223 void
224 disk_printtype(int unit, int type)
225 {
226 	printf(" drive %d: %c%c", unit, (int)MSCP_MID_CHAR(2, type),
227 	    (int)MSCP_MID_CHAR(1, type));
228 	if (MSCP_MID_ECH(0, type))
229 		printf("%c", (int)MSCP_MID_CHAR(0, type));
230 	printf("%d\n", MSCP_MID_NUM(type));
231 }
232 
233 /*
234  * Be sure that the pages we want to do DMA to is actually there
235  * by faking page-faults if necessary. If given a map-register address,
236  * also map it in.
237  */
238 void
239 disk_reallymapin(struct buf *bp, struct pte *map, int reg, int flag)
240 {
241 	struct proc *p;
242 	volatile pt_entry_t *io;
243 	pt_entry_t *pte;
244 	struct pcb *pcb;
245 	int pfnum, npf, o;
246 	caddr_t addr;
247 
248 	o = (int)bp->b_data & VAX_PGOFSET;
249 	npf = vax_btoc(bp->b_bcount + o) + 1;
250 	addr = bp->b_data;
251 	p = bp->b_proc;
252 
253 	/*
254 	 * Get a pointer to the pte pointing out the first virtual address.
255 	 * Use different ways in kernel and user space.
256 	 */
257 	if ((bp->b_flags & B_PHYS) == 0) {
258 		pte = kvtopte(addr);
259 		if (p == 0)
260 			p = &proc0;
261 	} else {
262 		pcb = &p->p_addr->u_pcb;
263 		pte = uvtopte(addr, pcb);
264 	}
265 
266 	if (map) {
267 		io = &map[reg];
268 		while (--npf > 0) {
269 			pfnum = pte->pg_pfn;
270 			if (pfnum == 0)
271 				panic("mapin zero entry");
272 			pte++;
273 			*(int *)io++ = pfnum | flag;
274 		}
275 		*(int *)io = 0;
276 	}
277 }
278