BSD 4_3_Tahoe release
[unix-history] / usr / src / sys / sys / ufs_disksubr.c
CommitLineData
da7c5cc6 1/*
1ad7f5c8 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
ca67e7b4
C
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
da7c5cc6 5 *
ca67e7b4 6 * @(#)ufs_disksubr.c 7.10 (Berkeley) 6/11/88
da7c5cc6 7 */
200a8f27 8
97934dfa
MK
9#include "param.h"
10#include "systm.h"
11#include "buf.h"
12#include "disklabel.h"
1ad7f5c8 13#include "syslog.h"
ca67e7b4
C
14
15#include "dir.h"
9573c71c
MK
16#include "user.h"
17
200a8f27 18/*
0d67fde4
BJ
19 * Seek sort for disks. We depend on the driver
20 * which calls us using b_resid as the current cylinder number.
21 *
22 * The argument dp structure holds a b_actf activity chain pointer
23 * on which we keep two queues, sorted in ascending cylinder order.
24 * The first queue holds those requests which are positioned after
25 * the current cylinder (in the first request); the second holds
26 * requests which came in after their cylinder number was passed.
27 * Thus we implement a one way scan, retracting after reaching the
28 * end of the drive to the first request on the second queue,
29 * at which time it becomes the first queue.
30 *
31 * A one-way scan is natural because of the way UNIX read-ahead
32 * blocks are allocated.
200a8f27
BJ
33 */
34
200a8f27
BJ
35#define b_cylin b_resid
36
37disksort(dp, bp)
0d67fde4 38 register struct buf *dp, *bp;
200a8f27
BJ
39{
40 register struct buf *ap;
200a8f27 41
0d67fde4
BJ
42 /*
43 * If nothing on the activity queue, then
44 * we become the only thing.
45 */
200a8f27
BJ
46 ap = dp->b_actf;
47 if(ap == NULL) {
48 dp->b_actf = bp;
49 dp->b_actl = bp;
50 bp->av_forw = NULL;
51 return;
52 }
0d67fde4
BJ
53 /*
54 * If we lie after the first (currently active)
55 * request, then we must locate the second request list
56 * and add ourselves to it.
57 */
58 if (bp->b_cylin < ap->b_cylin) {
59 while (ap->av_forw) {
60 /*
61 * Check for an ``inversion'' in the
62 * normally ascending cylinder numbers,
63 * indicating the start of the second request list.
64 */
65 if (ap->av_forw->b_cylin < ap->b_cylin) {
66 /*
67 * Search the second request list
68 * for the first request at a larger
69 * cylinder number. We go before that;
70 * if there is no such request, we go at end.
71 */
72 do {
73 if (bp->b_cylin < ap->av_forw->b_cylin)
74 goto insert;
667e5665
MK
75 if (bp->b_cylin == ap->av_forw->b_cylin &&
76 bp->b_blkno < ap->av_forw->b_blkno)
77 goto insert;
0d67fde4
BJ
78 ap = ap->av_forw;
79 } while (ap->av_forw);
80 goto insert; /* after last */
81 }
82 ap = ap->av_forw;
200a8f27 83 }
0d67fde4
BJ
84 /*
85 * No inversions... we will go after the last, and
86 * be the first request in the second request list.
87 */
88 goto insert;
200a8f27 89 }
0d67fde4
BJ
90 /*
91 * Request is at/after the current request...
92 * sort in the first request list.
93 */
94 while (ap->av_forw) {
95 /*
96 * We want to go after the current request
97 * if there is an inversion after it (i.e. it is
98 * the end of the first request list), or if
99 * the next request is a larger cylinder than our request.
100 */
101 if (ap->av_forw->b_cylin < ap->b_cylin ||
667e5665
MK
102 bp->b_cylin < ap->av_forw->b_cylin ||
103 (bp->b_cylin == ap->av_forw->b_cylin &&
104 bp->b_blkno < ap->av_forw->b_blkno))
0d67fde4
BJ
105 goto insert;
106 ap = ap->av_forw;
107 }
108 /*
109 * Neither a second list nor a larger
110 * request... we go at the end of the first list,
111 * which is the same as the end of the whole schebang.
112 */
113insert:
114 bp->av_forw = ap->av_forw;
115 ap->av_forw = bp;
116 if (ap == dp->b_actl)
200a8f27
BJ
117 dp->b_actl = bp;
118}
97934dfa 119
9573c71c
MK
120/*
121 * Attempt to read a disk label from a device
122 * using the indicated stategy routine.
123 * The label must be partly set up before this:
124 * secpercyl and anything required in the strategy routine
125 * (e.g., sector size) must be filled in before calling us.
126 * Returns null on success and an error string on failure.
127 */
128char *
129readdisklabel(dev, strat, lp)
130 dev_t dev;
131 int (*strat)();
132 register struct disklabel *lp;
133{
134 register struct buf *bp;
135 struct disklabel *dlp;
136 char *msg = NULL;
137
138 if (lp->d_secperunit == 0)
139 lp->d_secperunit = 0x1fffffff;
140 lp->d_npartitions = 1;
141 if (lp->d_partitions[0].p_size == 0)
142 lp->d_partitions[0].p_size = 0x1fffffff;
143 lp->d_partitions[0].p_offset = 0;
144
d3633d66 145 bp = geteblk((int)lp->d_secsize);
9573c71c
MK
146 bp->b_dev = dev;
147 bp->b_blkno = LABELSECTOR;
cd6cd535 148 bp->b_bcount = lp->d_secsize;
9573c71c
MK
149 bp->b_flags = B_BUSY | B_READ;
150 bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
151 (*strat)(bp);
ca67e7b4
C
152 biowait(bp);
153 if (bp->b_flags & B_ERROR) {
154 u.u_error = 0; /* XXX */
9573c71c 155 msg = "I/O error";
cd6cd535
MK
156 } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
157 dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
158 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
159 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
160 if (msg == NULL)
161 msg = "no disk label";
162 } else if (dkcksum(dlp) != 0)
9573c71c 163 msg = "disk label corrupted";
cd6cd535 164 else {
9573c71c 165 *lp = *dlp;
cd6cd535
MK
166 msg = NULL;
167 break;
168 }
9573c71c 169 }
cd6cd535
MK
170 if (lp->d_npartitions > MAXPARTITIONS)
171 lp->d_npartitions = MAXPARTITIONS;
9573c71c
MK
172 bp->b_flags = B_INVAL | B_AGE;
173 brelse(bp);
174 return (msg);
175}
176
667e5665
MK
177/*
178 * Check new disk label for sensibility
179 * before setting it.
180 */
181setdisklabel(olp, nlp, openmask)
182 register struct disklabel *olp, *nlp;
183 u_long openmask;
184{
185 register i;
186 register struct partition *opp, *npp;
187
188 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
189 dkcksum(nlp) != 0)
190 return (EINVAL);
5adcb337 191 while ((i = ffs((long)openmask)) != 0) {
667e5665
MK
192 i--;
193 openmask &= ~(1 << i);
194 if (nlp->d_npartitions <= i)
195 return (EBUSY);
196 opp = &olp->d_partitions[i];
197 npp = &nlp->d_partitions[i];
198 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
199 return (EBUSY);
200 /*
201 * Copy internally-set partition information
202 * if new label doesn't include it. XXX
203 */
204 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
205 npp->p_fstype = opp->p_fstype;
206 npp->p_fsize = opp->p_fsize;
207 npp->p_frag = opp->p_frag;
208 npp->p_cpg = opp->p_cpg;
209 }
210 }
d3633d66
MK
211 nlp->d_checksum = 0;
212 nlp->d_checksum = dkcksum(nlp);
667e5665
MK
213 *olp = *nlp;
214 return (0);
215}
216
217/* encoding of disk minor numbers, should be elsewhere... */
218#define dkunit(dev) (minor(dev) >> 3)
219#define dkpart(dev) (minor(dev) & 07)
220#define dkminor(unit, part) (((unit) << 3) | (part))
221
222/*
223 * Write disk label back to device after modification.
224 */
225writedisklabel(dev, strat, lp)
226 dev_t dev;
227 int (*strat)();
228 register struct disklabel *lp;
229{
230 struct buf *bp;
231 struct disklabel *dlp;
232 int labelpart;
233 int error = 0;
234
235 labelpart = dkpart(dev);
236 if (lp->d_partitions[labelpart].p_offset != 0) {
237 if (lp->d_partitions[0].p_offset != 0)
238 return (EXDEV); /* not quite right */
239 labelpart = 0;
240 }
d3633d66 241 bp = geteblk((int)lp->d_secsize);
667e5665
MK
242 bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart));
243 bp->b_blkno = LABELSECTOR;
244 bp->b_bcount = lp->d_secsize;
245 bp->b_flags = B_READ;
246 (*strat)(bp);
ca67e7b4
C
247 biowait(bp);
248 if (bp->b_flags & B_ERROR) {
249 error = u.u_error; /* XXX */
250 u.u_error = 0;
d3633d66 251 goto done;
ca67e7b4 252 }
d3633d66
MK
253 for (dlp = (struct disklabel *)bp->b_un.b_addr;
254 dlp <= (struct disklabel *)
255 (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
256 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
257 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
258 dkcksum(dlp) == 0) {
259 *dlp = *lp;
260 bp->b_flags = B_WRITE;
261 (*strat)(bp);
ca67e7b4
C
262 biowait(bp);
263 if (bp->b_flags & B_ERROR) {
264 error = u.u_error; /* XXX */
265 u.u_error = 0;
266 }
d3633d66
MK
267 goto done;
268 }
667e5665 269 }
d3633d66
MK
270 error = ESRCH;
271done:
667e5665
MK
272 brelse(bp);
273 return (error);
274}
275
97934dfa
MK
276/*
277 * Compute checksum for disk label.
278 */
279dkcksum(lp)
280 register struct disklabel *lp;
281{
282 register u_short *start, *end;
283 register u_short sum = 0;
284
285 start = (u_short *)lp;
286 end = (u_short *)&lp->d_partitions[lp->d_npartitions];
287 while (start < end)
288 sum ^= *start++;
289 return (sum);
290}
1ad7f5c8
MK
291
292/*
293 * Disk error is the preface to plaintive error messages
294 * about failing disk transfers. It prints messages of the form
05de9101
MK
295
296hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
297
1ad7f5c8
MK
298 * if the offset of the error in the transfer and a disk label
299 * are both available. blkdone should be -1 if the position of the error
300 * is unknown; the disklabel pointer may be null from drivers that have not
301 * been converted to use them. The message is printed with printf
302 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
303 * The message should be completed (with at least a newline) with printf
304 * or addlog, respectively. There is no trailing space.
305 */
306diskerr(bp, dname, what, pri, blkdone, lp)
307 register struct buf *bp;
308 char *dname, *what;
309 int pri, blkdone;
310 register struct disklabel *lp;
311{
312 int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev);
313 register int (*pr)(), sn;
314 char partname = 'a' + part;
315 extern printf(), addlog();
316
317 if (pri != LOG_PRINTF) {
318 log(pri, "");
319 pr = addlog;
320 } else
321 pr = printf;
322 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what,
323 bp->b_flags & B_READ ? "read" : "writ");
324 sn = bp->b_blkno;
325 if (bp->b_bcount <= DEV_BSIZE)
326 (*pr)("%d", sn);
327 else {
328 if (blkdone >= 0) {
329 sn += blkdone;
330 (*pr)("%d of ", sn);
331 }
332 (*pr)("%d-%d", bp->b_blkno,
333 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE);
334 }
f2a9617b
MK
335 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
336#ifdef tahoe
337 sn *= DEV_BSIZE / lp->d_secsize; /* XXX */
338#endif
1ad7f5c8 339 sn += lp->d_partitions[part].p_offset;
05de9101
MK
340 (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn,
341 sn / lp->d_secpercyl);
342 sn %= lp->d_secpercyl;
ca67e7b4 343 (*pr)(" tn %d sn %d)", sn / lp->d_ntracks, sn % lp->d_ntracks);
1ad7f5c8
MK
344 }
345}