try not to send net unreachables for subnets
[unix-history] / usr / src / sys / ufs / ffs / ufs_disksubr.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
cd6cd535 6 * @(#)ufs_disksubr.c 7.4 (Berkeley) %G%
da7c5cc6 7 */
200a8f27 8
97934dfa
MK
9#include "param.h"
10#include "systm.h"
11#include "buf.h"
12#include "disklabel.h"
13
9573c71c
MK
14#include "dir.h"
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;
74 ap = ap->av_forw;
75 } while (ap->av_forw);
76 goto insert; /* after last */
77 }
78 ap = ap->av_forw;
200a8f27 79 }
0d67fde4
BJ
80 /*
81 * No inversions... we will go after the last, and
82 * be the first request in the second request list.
83 */
84 goto insert;
200a8f27 85 }
0d67fde4
BJ
86 /*
87 * Request is at/after the current request...
88 * sort in the first request list.
89 */
90 while (ap->av_forw) {
91 /*
92 * We want to go after the current request
93 * if there is an inversion after it (i.e. it is
94 * the end of the first request list), or if
95 * the next request is a larger cylinder than our request.
96 */
97 if (ap->av_forw->b_cylin < ap->b_cylin ||
98 bp->b_cylin < ap->av_forw->b_cylin)
99 goto insert;
100 ap = ap->av_forw;
101 }
102 /*
103 * Neither a second list nor a larger
104 * request... we go at the end of the first list,
105 * which is the same as the end of the whole schebang.
106 */
107insert:
108 bp->av_forw = ap->av_forw;
109 ap->av_forw = bp;
110 if (ap == dp->b_actl)
200a8f27
BJ
111 dp->b_actl = bp;
112}
97934dfa 113
9573c71c
MK
114/*
115 * Attempt to read a disk label from a device
116 * using the indicated stategy routine.
117 * The label must be partly set up before this:
118 * secpercyl and anything required in the strategy routine
119 * (e.g., sector size) must be filled in before calling us.
120 * Returns null on success and an error string on failure.
121 */
122char *
123readdisklabel(dev, strat, lp)
124 dev_t dev;
125 int (*strat)();
126 register struct disklabel *lp;
127{
128 register struct buf *bp;
129 struct disklabel *dlp;
130 char *msg = NULL;
131
132 if (lp->d_secperunit == 0)
133 lp->d_secperunit = 0x1fffffff;
134 lp->d_npartitions = 1;
135 if (lp->d_partitions[0].p_size == 0)
136 lp->d_partitions[0].p_size = 0x1fffffff;
137 lp->d_partitions[0].p_offset = 0;
138
cd6cd535 139 bp = geteblk(lp->d_secsize);
9573c71c
MK
140 bp->b_dev = dev;
141 bp->b_blkno = LABELSECTOR;
cd6cd535 142 bp->b_bcount = lp->d_secsize;
9573c71c
MK
143 bp->b_flags = B_BUSY | B_READ;
144 bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
145 (*strat)(bp);
146 biowait(bp);
147 if (bp->b_flags & B_ERROR) {
148 u.u_error = 0; /* XXX */
149 msg = "I/O error";
cd6cd535
MK
150 } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
151 dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
152 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
153 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
154 if (msg == NULL)
155 msg = "no disk label";
156 } else if (dkcksum(dlp) != 0)
9573c71c 157 msg = "disk label corrupted";
cd6cd535 158 else {
9573c71c 159 *lp = *dlp;
cd6cd535
MK
160 msg = NULL;
161 break;
162 }
9573c71c 163 }
cd6cd535
MK
164 if (lp->d_npartitions > MAXPARTITIONS)
165 lp->d_npartitions = MAXPARTITIONS;
9573c71c
MK
166 bp->b_flags = B_INVAL | B_AGE;
167 brelse(bp);
168 return (msg);
169}
170
97934dfa
MK
171/*
172 * Compute checksum for disk label.
173 */
174dkcksum(lp)
175 register struct disklabel *lp;
176{
177 register u_short *start, *end;
178 register u_short sum = 0;
179
180 start = (u_short *)lp;
181 end = (u_short *)&lp->d_partitions[lp->d_npartitions];
182 while (start < end)
183 sum ^= *start++;
184 return (sum);
185}