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