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 * from: @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 39 * $Id: subr_disk.c,v 1.11 1994/05/19 03:43:13 mycroft Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/buf.h> 45 #include <sys/disklabel.h> 46 #include <sys/syslog.h> 47 48 /* 49 * Seek sort for disks. We depend on the driver which calls us using b_resid 50 * as the current cylinder number. 51 * 52 * The argument ap structure holds a b_actf activity chain pointer on which we 53 * keep two queues, sorted in ascending cylinder order. The first queue holds 54 * those requests which are positioned after the current cylinder (in the first 55 * request); the second holds requests which came in after their cylinder number 56 * was passed. Thus we implement a one way scan, retracting after reaching the 57 * end of the drive to the first request on the second queue, at which time it 58 * becomes the first queue. 59 * 60 * A one-way scan is natural because of the way UNIX read-ahead blocks are 61 * allocated. 62 */ 63 64 /* 65 * For portability with historic industry practice, the 66 * cylinder number has to be maintained in the `b_resid' 67 * field. 68 */ 69 #define b_cylinder b_resid 70 71 void 72 disksort(ap, bp) 73 register struct buf *ap, *bp; 74 { 75 register struct buf *bq; 76 77 /* If the queue is empty, then it's easy. */ 78 if (ap->b_actf == NULL) { 79 bp->b_actf = NULL; 80 ap->b_actf = bp; 81 return; 82 } 83 84 /* 85 * If we lie after the first (currently active) request, then we 86 * must locate the second request list and add ourselves to it. 87 */ 88 bq = ap->b_actf; 89 if (bp->b_cylinder < bq->b_cylinder) { 90 while (bq->b_actf) { 91 /* 92 * Check for an ``inversion'' in the normally ascending 93 * cylinder numbers, indicating the start of the second 94 * request list. 95 */ 96 if (bq->b_actf->b_cylinder < bq->b_cylinder) { 97 /* 98 * Search the second request list for the first 99 * request at a larger cylinder number. We go 100 * before that; if there is no such request, we 101 * go at end. 102 */ 103 do { 104 if (bp->b_cylinder < 105 bq->b_actf->b_cylinder) 106 goto insert; 107 if (bp->b_cylinder == 108 bq->b_actf->b_cylinder && 109 bp->b_blkno < bq->b_actf->b_blkno) 110 goto insert; 111 bq = bq->b_actf; 112 } while (bq->b_actf); 113 goto insert; /* after last */ 114 } 115 bq = bq->b_actf; 116 } 117 /* 118 * No inversions... we will go after the last, and 119 * be the first request in the second request list. 120 */ 121 goto insert; 122 } 123 /* 124 * Request is at/after the current request... 125 * sort in the first request list. 126 */ 127 while (bq->b_actf) { 128 /* 129 * We want to go after the current request if there is an 130 * inversion after it (i.e. it is the end of the first 131 * request list), or if the next request is a larger cylinder 132 * than our request. 133 */ 134 if (bq->b_actf->b_cylinder < bq->b_cylinder || 135 bp->b_cylinder < bq->b_actf->b_cylinder || 136 (bp->b_cylinder == bq->b_actf->b_cylinder && 137 bp->b_blkno < bq->b_actf->b_blkno)) 138 goto insert; 139 bq = bq->b_actf; 140 } 141 /* 142 * Neither a second list nor a larger request... we go at the end of 143 * the first list, which is the same as the end of the whole schebang. 144 */ 145 insert: bp->b_actf = bq->b_actf; 146 bq->b_actf = bp; 147 } 148 149 /* encoding of disk minor numbers, should be elsewhere... */ 150 #define dkunit(dev) (minor(dev) >> 3) 151 #define dkpart(dev) (minor(dev) & 07) 152 #define dkminor(unit, part) (((unit) << 3) | (part)) 153 154 /* 155 * Compute checksum for disk label. 156 */ 157 u_int 158 dkcksum(lp) 159 register struct disklabel *lp; 160 { 161 register u_short *start, *end; 162 register u_short sum = 0; 163 164 start = (u_short *)lp; 165 end = (u_short *)&lp->d_partitions[lp->d_npartitions]; 166 while (start < end) 167 sum ^= *start++; 168 return (sum); 169 } 170 171 /* 172 * Disk error is the preface to plaintive error messages 173 * about failing disk transfers. It prints messages of the form 174 175 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) 176 177 * if the offset of the error in the transfer and a disk label 178 * are both available. blkdone should be -1 if the position of the error 179 * is unknown; the disklabel pointer may be null from drivers that have not 180 * been converted to use them. The message is printed with printf 181 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. 182 * The message should be completed (with at least a newline) with printf 183 * or addlog, respectively. There is no trailing space. 184 */ 185 void 186 diskerr(bp, dname, what, pri, blkdone, lp) 187 register struct buf *bp; 188 char *dname, *what; 189 int pri, blkdone; 190 register struct disklabel *lp; 191 { 192 int unit = dkunit(bp->b_dev), part = dkpart(bp->b_dev); 193 register void (*pr) __P((const char *, ...)); 194 char partname = 'a' + part; 195 int sn; 196 197 if (pri != LOG_PRINTF) { 198 log(pri, ""); 199 pr = addlog; 200 } else 201 pr = printf; 202 (*pr)("%s%d%c: %s %sing fsbn ", dname, unit, partname, what, 203 bp->b_flags & B_READ ? "read" : "writ"); 204 sn = bp->b_blkno; 205 if (bp->b_bcount <= DEV_BSIZE) 206 (*pr)("%d", sn); 207 else { 208 if (blkdone >= 0) { 209 sn += blkdone; 210 (*pr)("%d of ", sn); 211 } 212 (*pr)("%d-%d", bp->b_blkno, 213 bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE); 214 } 215 if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { 216 #ifdef tahoe 217 sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ 218 #endif 219 sn += lp->d_partitions[part].p_offset; 220 (*pr)(" (%s%d bn %d; cn %d", dname, unit, sn, 221 sn / lp->d_secpercyl); 222 sn %= lp->d_secpercyl; 223 (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); 224 } 225 } 226