ATAng stage 6: Comment-only. Many thanks to David Rhodus for generating
[dragonfly.git] / sys / vfs / ufs / ufs_disksubr.c
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)ufs_disksubr.c      8.5 (Berkeley) 1/21/94
39  * $FreeBSD: src/sys/ufs/ufs/ufs_disksubr.c,v 1.44.2.3 2001/03/05 05:42:19 obrien Exp $
40  * $DragonFly: src/sys/vfs/ufs/Attic/ufs_disksubr.c,v 1.5 2003/07/26 22:04:27 rob Exp $
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46 #include <sys/buf.h>
47 #include <sys/conf.h>
48 #include <sys/disklabel.h>
49 #include <sys/diskslice.h>
50 #include <sys/syslog.h>
51 #include <sys/device.h>
52
53 #include <sys/buf2.h>
54
55 /*
56  * Seek sort for disks.
57  *
58  * The buf_queue keep two queues, sorted in ascending block order.  The first
59  * queue holds those requests which are positioned after the current block
60  * (in the first request); the second, which starts at queue->switch_point,
61  * holds requests which came in after their block number was passed.  Thus
62  * we implement a one way scan, retracting after reaching the end of the drive
63  * to the first request on the second queue, at which time it becomes the
64  * first queue.
65  *
66  * A one-way scan is natural because of the way UNIX read-ahead blocks are
67  * allocated.
68  */
69
70 void
71 bufqdisksort(bufq, bp)
72         struct buf_queue_head *bufq;
73         struct buf *bp;
74 {
75         struct buf *bq;
76         struct buf *bn;
77         struct buf *be;
78         
79         be = TAILQ_LAST(&bufq->queue, buf_queue);
80         /*
81          * If the queue is empty or we are an
82          * ordered transaction, then it's easy.
83          */
84         if ((bq = bufq_first(bufq)) == NULL
85          || (bp->b_flags & B_ORDERED) != 0) {
86                 bufq_insert_tail(bufq, bp);
87                 return;
88         } else if (bufq->insert_point != NULL) {
89
90                 /*
91                  * A certain portion of the list is
92                  * "locked" to preserve ordering, so
93                  * we can only insert after the insert
94                  * point.
95                  */
96                 bq = bufq->insert_point;
97         } else {
98
99                 /*
100                  * If we lie before the last removed (currently active)
101                  * request, and are not inserting ourselves into the
102                  * "locked" portion of the list, then we must add ourselves
103                  * to the second request list.
104                  */
105                 if (bp->b_pblkno < bufq->last_pblkno) {
106
107                         bq = bufq->switch_point;
108                         /*
109                          * If we are starting a new secondary list,
110                          * then it's easy.
111                          */
112                         if (bq == NULL) {
113                                 bufq->switch_point = bp;
114                                 bufq_insert_tail(bufq, bp);
115                                 return;
116                         }
117                         /*
118                          * If we lie ahead of the current switch point,
119                          * insert us before the switch point and move
120                          * the switch point.
121                          */
122                         if (bp->b_pblkno < bq->b_pblkno) {
123                                 bufq->switch_point = bp;
124                                 TAILQ_INSERT_BEFORE(bq, bp, b_act);
125                                 return;
126                         }
127                 } else {
128                         if (bufq->switch_point != NULL)
129                                 be = TAILQ_PREV(bufq->switch_point,
130                                                 buf_queue, b_act);
131                         /*
132                          * If we lie between last_pblkno and bq,
133                          * insert before bq.
134                          */
135                         if (bp->b_pblkno < bq->b_pblkno) {
136                                 TAILQ_INSERT_BEFORE(bq, bp, b_act);
137                                 return;
138                         }
139                 }
140         }
141
142         /*
143          * Request is at/after our current position in the list.
144          * Optimize for sequential I/O by seeing if we go at the tail.
145          */
146         if (bp->b_pblkno > be->b_pblkno) {
147                 TAILQ_INSERT_AFTER(&bufq->queue, be, bp, b_act);
148                 return;
149         }
150
151         /* Otherwise, insertion sort */
152         while ((bn = TAILQ_NEXT(bq, b_act)) != NULL) {
153                 
154                 /*
155                  * We want to go after the current request if it is the end
156                  * of the first request list, or if the next request is a
157                  * larger cylinder than our request.
158                  */
159                 if (bn == bufq->switch_point
160                  || bp->b_pblkno < bn->b_pblkno)
161                         break;
162                 bq = bn;
163         }
164         TAILQ_INSERT_AFTER(&bufq->queue, bq, bp, b_act);
165 }
166
167
168 /*
169  * Attempt to read a disk label from a device using the indicated strategy
170  * routine.  The label must be partly set up before this: secpercyl, secsize
171  * and anything required in the strategy routine (e.g., dummy bounds for the
172  * partition containing the label) must be filled in before calling us.
173  * Returns NULL on success and an error string on failure.
174  */
175 char *
176 readdisklabel(dev, lp)
177         dev_t dev;
178         struct disklabel *lp;
179 {
180         struct buf *bp;
181         struct disklabel *dlp;
182         char *msg = NULL;
183
184         bp = geteblk((int)lp->d_secsize);
185         bp->b_dev = dev;
186         bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE);
187         bp->b_bcount = lp->d_secsize;
188         bp->b_flags &= ~B_INVAL;
189         bp->b_flags |= B_READ;
190         BUF_STRATEGY(bp, 1);
191         if (biowait(bp))
192                 msg = "I/O error";
193         else for (dlp = (struct disklabel *)bp->b_data;
194             dlp <= (struct disklabel *)((char *)bp->b_data +
195             lp->d_secsize - sizeof(*dlp));
196             dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
197                 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
198                         if (msg == NULL)
199                                 msg = "no disk label";
200                 } else if (dlp->d_npartitions > MAXPARTITIONS ||
201                            dkcksum(dlp) != 0)
202                         msg = "disk label corrupted";
203                 else {
204                         *lp = *dlp;
205                         msg = NULL;
206                         break;
207                 }
208         }
209         bp->b_flags |= B_INVAL | B_AGE;
210         brelse(bp);
211         return (msg);
212 }
213
214 /*
215  * Check new disk label for sensibility before setting it.
216  */
217 int
218 setdisklabel(olp, nlp, openmask)
219         struct disklabel *olp, *nlp;
220         u_long openmask;
221 {
222         int i;
223         struct partition *opp, *npp;
224
225         /*
226          * Check it is actually a disklabel we are looking at.
227          */
228         if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
229             dkcksum(nlp) != 0)
230                 return (EINVAL);
231         /*
232          * For each partition that we think is open,
233          */
234         while ((i = ffs((long)openmask)) != 0) {
235                 i--;
236                 /*
237                  * Check it is not changing....
238                  */
239                 openmask &= ~(1 << i);
240                 if (nlp->d_npartitions <= i)
241                         return (EBUSY);
242                 opp = &olp->d_partitions[i];
243                 npp = &nlp->d_partitions[i];
244                 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
245                         return (EBUSY);
246                 /*
247                  * Copy internally-set partition information
248                  * if new label doesn't include it.             XXX
249                  * (If we are using it then we had better stay the same type)
250                  * This is possibly dubious, as someone else noted (XXX)
251                  */
252                 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
253                         npp->p_fstype = opp->p_fstype;
254                         npp->p_fsize = opp->p_fsize;
255                         npp->p_frag = opp->p_frag;
256                         npp->p_cpg = opp->p_cpg;
257                 }
258         }
259         nlp->d_checksum = 0;
260         nlp->d_checksum = dkcksum(nlp);
261         *olp = *nlp;
262         return (0);
263 }
264
265 /*
266  * Write disk label back to device after modification.
267  */
268 int
269 writedisklabel(dev, lp)
270         dev_t dev;
271         struct disklabel *lp;
272 {
273         struct buf *bp;
274         struct disklabel *dlp;
275         int error = 0;
276
277         if (lp->d_partitions[RAW_PART].p_offset != 0)
278                 return (EXDEV);                 /* not quite right */
279         bp = geteblk((int)lp->d_secsize);
280         bp->b_dev = dkmodpart(dev, RAW_PART);
281         bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE);
282         bp->b_bcount = lp->d_secsize;
283 #if 1
284         /*
285          * We read the label first to see if it's there,
286          * in which case we will put ours at the same offset into the block..
287          * (I think this is stupid [Julian])
288          * Note that you can't write a label out over a corrupted label!
289          * (also stupid.. how do you write the first one? by raw writes?)
290          */
291         bp->b_flags &= ~B_INVAL;
292         bp->b_flags |= B_READ;
293         BUF_STRATEGY(bp, 1);
294         error = biowait(bp);
295         if (error)
296                 goto done;
297         for (dlp = (struct disklabel *)bp->b_data;
298             dlp <= (struct disklabel *)
299               ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
300             dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
301                 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
302                     dkcksum(dlp) == 0) {
303                         *dlp = *lp;
304                         bp->b_flags &= ~(B_DONE | B_READ);
305                         bp->b_flags |= B_WRITE;
306 #ifdef __alpha__
307                         alpha_fix_srm_checksum(bp);
308 #endif
309                         BUF_STRATEGY(bp, 1);
310                         error = biowait(bp);
311                         goto done;
312                 }
313         }
314         error = ESRCH;
315 done:
316 #else
317         bzero(bp->b_data, lp->d_secsize);
318         dlp = (struct disklabel *)bp->b_data;
319         *dlp = *lp;
320         bp->b_flags &= ~B_INVAL;
321         bp->b_flags |= B_WRITE;
322         BUF_STRATEGY(bp, 1);
323         error = biowait(bp);
324 #endif
325         bp->b_flags |= B_INVAL | B_AGE;
326         brelse(bp);
327         return (error);
328 }
329
330 /*
331  * Disk error is the preface to plaintive error messages
332  * about failing disk transfers.  It prints messages of the form
333
334 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
335
336  * if the offset of the error in the transfer and a disk label
337  * are both available.  blkdone should be -1 if the position of the error
338  * is unknown; the disklabel pointer may be null from drivers that have not
339  * been converted to use them.  The message is printed with printf
340  * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
341  * The message should be completed (with at least a newline) with printf
342  * or addlog, respectively.  There is no trailing space.
343  */
344 void
345 diskerr(bp, what, pri, blkdone, lp)
346         struct buf *bp;
347         char *what;
348         int pri, blkdone;
349         struct disklabel *lp;
350 {
351         int unit = dkunit(bp->b_dev);
352         int slice = dkslice(bp->b_dev);
353         int part = dkpart(bp->b_dev);
354         char partname[2];
355         char *sname;
356         daddr_t sn;
357
358         sname = dsname(bp->b_dev, unit, slice, part, partname);
359         printf("%s%s: %s %sing fsbn ", sname, partname, what,
360               bp->b_flags & B_READ ? "read" : "writ");
361         sn = bp->b_blkno;
362         if (bp->b_bcount <= DEV_BSIZE)
363                 printf("%ld", (long)sn);
364         else {
365                 if (blkdone >= 0) {
366                         sn += blkdone;
367                         printf("%ld of ", (long)sn);
368                 }
369                 printf("%ld-%ld", (long)bp->b_blkno,
370                     (long)(bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE));
371         }
372         if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) {
373 #ifdef tahoe
374                 sn *= DEV_BSIZE / lp->d_secsize;                /* XXX */
375 #endif
376                 sn += lp->d_partitions[part].p_offset;
377                 /*
378                  * XXX should add slice offset and not print the slice,
379                  * but we don't know the slice pointer.
380                  * XXX should print bp->b_pblkno so that this will work
381                  * independent of slices, labels and bad sector remapping,
382                  * but some drivers don't set bp->b_pblkno.
383                  */
384                 printf(" (%s bn %ld; cn %ld", sname, (long)sn,
385                     (long)(sn / lp->d_secpercyl));
386                 sn %= (long)lp->d_secpercyl;
387                 printf(" tn %ld sn %ld)", (long)(sn / lp->d_nsectors),
388                     (long)(sn % lp->d_nsectors));
389         }
390 }