2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * ----------------------------------------------------------------------------
35 * "THE BEER-WARE LICENSE" (Revision 42):
36 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
37 * can do whatever you want with this stuff. If we meet some day, and you think
38 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
39 * ----------------------------------------------------------------------------
41 * Copyright (c) 1982, 1986, 1988, 1993
42 * The Regents of the University of California. All rights reserved.
43 * (c) UNIX System Laboratories, Inc.
44 * All or some portions of this file are derived from material licensed
45 * to the University of California by American Telephone and Telegraph
46 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
47 * the permission of UNIX System Laboratories, Inc.
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. All advertising materials mentioning features or use of this software
58 * must display the following acknowledgement:
59 * This product includes software developed by the University of
60 * California, Berkeley and its contributors.
61 * 4. Neither the name of the University nor the names of its contributors
62 * may be used to endorse or promote products derived from this software
63 * without specific prior written permission.
65 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
77 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
78 * $FreeBSD: src/sys/kern/subr_disk.c,v 1.20.2.6 2001/10/05 07:14:57 peter Exp $
79 * $FreeBSD: src/sys/ufs/ufs/ufs_disksubr.c,v 1.44.2.3 2001/03/05 05:42:19 obrien Exp $
80 * $DragonFly: src/sys/kern/subr_disk.c,v 1.21 2006/02/17 19:18:06 dillon Exp $
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/kernel.h>
87 #include <sys/sysctl.h>
90 #include <sys/disklabel.h>
91 #include <sys/diskslice.h>
93 #include <sys/malloc.h>
94 #include <sys/sysctl.h>
95 #include <machine/md_var.h>
96 #include <sys/ctype.h>
97 #include <sys/syslog.h>
98 #include <sys/device.h>
99 #include <sys/msgport.h>
100 #include <sys/msgport2.h>
101 #include <sys/buf2.h>
103 static MALLOC_DEFINE(M_DISK
, "disk", "disk data");
105 static d_strategy_t diskstrategy
;
106 static d_open_t diskopen
;
107 static d_close_t diskclose
;
108 static d_ioctl_t diskioctl
;
109 static d_psize_t diskpsize
;
110 static d_clone_t diskclone
;
111 static int disk_putport(lwkt_port_t port
, lwkt_msg_t msg
);
113 static LIST_HEAD(, disk
) disklist
= LIST_HEAD_INITIALIZER(&disklist
);
116 * Create a slice and unit managed disk.
118 * Our port layer will be responsible for assigning blkno and handling
119 * high level partition operations, then forwarding the requests to the
122 * The disk_create() function clones the provided rawsw for creating a
123 * managed disk device. In addition, the cdevsw intercept port is
124 * changed to disk_putport, which is used to transform requests for the
125 * managed disk device.
127 * The raw device (based on rawsw) is returned to the caller, NOT the
128 * slice and unit managed cdev. The caller typically sets various
129 * driver parameters and IO limits on the returned rawdev which we must
130 * inherit when our managed device is opened.
133 disk_create(int unit
, struct disk
*dp
, int flags
, struct cdevsw
*rawsw
)
136 struct cdevsw
*devsw
;
139 * Create the raw backing device
141 compile_devsw(rawsw
);
142 rawdev
= make_dev(rawsw
, dkmakeminor(unit
, WHOLE_DISK_SLICE
, RAW_PART
),
143 UID_ROOT
, GID_OPERATOR
, 0640,
144 "%s%d", rawsw
->d_name
, unit
);
147 * Initialize our intercept port
149 bzero(dp
, sizeof(*dp
));
150 lwkt_initport(&dp
->d_port
, NULL
);
151 dp
->d_port
.mp_putport
= disk_putport
;
155 * We install a custom cdevsw rather then the passed cdevsw,
156 * and save our disk structure in d_data so we can get at it easily
157 * without any complex cloning code.
159 devsw
= cdevsw_add_override(rawdev
, dkunitmask(), dkmakeunit(unit
));
160 devsw
->d_port
= &dp
->d_port
;
162 devsw
->d_clone
= diskclone
;
164 dp
->d_rawdev
= rawdev
;
165 dp
->d_cdev
= make_dev(devsw
,
166 dkmakeminor(unit
, WHOLE_DISK_SLICE
, RAW_PART
),
167 UID_ROOT
, GID_OPERATOR
, 0640,
168 "%s%d", devsw
->d_name
, unit
);
170 dp
->d_dsflags
= flags
;
171 LIST_INSERT_HEAD(&disklist
, dp
, d_list
);
172 return (dp
->d_rawdev
);
176 * This routine is called when an adapter detaches. The higher level
177 * managed disk device is destroyed while the lower level raw device is
181 disk_destroy(struct disk
*disk
)
184 cdevsw_remove(disk
->d_devsw
, dkunitmask(),
185 dkmakeunit(dkunit(disk
->d_cdev
)));
186 LIST_REMOVE(disk
, d_list
);
189 destroy_all_dev(disk
->d_rawsw
, dkunitmask(),
190 dkmakeunit(dkunit(disk
->d_rawdev
)));
192 bzero(disk
, sizeof(*disk
));
196 disk_dumpcheck(dev_t dev
, u_int
*count
, u_int
*blkno
, u_int
*secsize
)
199 struct disklabel
*dl
;
207 dl
= dsgetlabel(dev
, dp
->d_slice
);
210 *count
= Maxmem
* (PAGE_SIZE
/ dl
->d_secsize
);
211 if (dumplo
<= LABELSECTOR
||
212 (dumplo
+ *count
> dl
->d_partitions
[dkpart(dev
)].p_size
))
214 boff
= dl
->d_partitions
[dkpart(dev
)].p_offset
+
215 dp
->d_slice
->dss_slices
[dkslice(dev
)].ds_offset
;
216 *blkno
= boff
+ dumplo
;
217 *secsize
= dl
->d_secsize
;
223 disk_invalidate (struct disk
*disk
)
226 dsgone(&disk
->d_slice
);
230 disk_enumerate(struct disk
*disk
)
233 return (LIST_FIRST(&disklist
));
235 return (LIST_NEXT(disk
, d_list
));
240 sysctl_disks(SYSCTL_HANDLER_ARGS
)
248 while ((disk
= disk_enumerate(disk
))) {
250 error
= SYSCTL_OUT(req
, " ", 1);
256 error
= SYSCTL_OUT(req
, disk
->d_rawdev
->si_name
,
257 strlen(disk
->d_rawdev
->si_name
));
261 error
= SYSCTL_OUT(req
, "", 1);
265 SYSCTL_PROC(_kern
, OID_AUTO
, disks
, CTLTYPE_STRING
| CTLFLAG_RD
, 0, NULL
,
266 sysctl_disks
, "A", "names of available disks");
269 * The port intercept functions
273 disk_putport(lwkt_port_t port
, lwkt_msg_t lmsg
)
275 struct disk
*disk
= (struct disk
*)port
;
276 cdevallmsg_t msg
= (cdevallmsg_t
)lmsg
;
279 switch(msg
->am_lmsg
.ms_cmd
.cm_op
) {
282 msg
->am_open
.msg
.dev
,
284 msg
->am_open
.devtype
,
289 msg
->am_close
.msg
.dev
,
291 msg
->am_close
.devtype
,
296 msg
->am_ioctl
.msg
.dev
,
302 case CDEV_CMD_STRATEGY
:
303 diskstrategy(msg
->am_strategy
.msg
.dev
, msg
->am_strategy
.bio
);
307 msg
->am_psize
.result
= diskpsize(msg
->am_psize
.msg
.dev
);
311 error
= physio(msg
->am_read
.msg
.dev
,
312 msg
->am_read
.uio
, msg
->am_read
.ioflag
);
315 error
= physio(msg
->am_write
.msg
.dev
,
316 msg
->am_write
.uio
, msg
->am_write
.ioflag
);
319 case CDEV_CMD_KQFILTER
:
325 error
= disk_dumpcheck(msg
->am_dump
.msg
.dev
,
328 &msg
->am_dump
.secsize
);
330 msg
->am_dump
.msg
.dev
= disk
->d_rawdev
;
331 error
= lwkt_forwardmsg(disk
->d_rawdev
->si_port
,
332 &msg
->am_dump
.msg
.msg
);
333 printf("error2 %d\n", error
);
344 * When new device entries are instantiated, make sure they inherit our
345 * si_disk structure and block and iosize limits from the raw device.
347 * This routine is always called synchronously in the context of the
350 * XXX The various io and block size constraints are not always initialized
351 * properly by devices.
359 dp
= dev
->si_devsw
->d_data
;
360 KKASSERT(dp
!= NULL
);
362 dev
->si_iosize_max
= dp
->d_rawdev
->si_iosize_max
;
363 dev
->si_bsize_phys
= dp
->d_rawdev
->si_bsize_phys
;
364 dev
->si_bsize_best
= dp
->d_rawdev
->si_bsize_best
;
369 * Open a disk device or partition.
373 diskopen(dev_t dev
, int oflags
, int devtype
, struct thread
*td
)
379 * dp can't be NULL here XXX.
387 * Deal with open races
389 while (dp
->d_flags
& DISKFLAG_LOCK
) {
390 dp
->d_flags
|= DISKFLAG_WANTED
;
391 error
= tsleep(dp
, PCATCH
, "diskopen", hz
);
395 dp
->d_flags
|= DISKFLAG_LOCK
;
398 * Open the underlying raw device.
400 if (!dsisopen(dp
->d_slice
)) {
402 if (!pdev
->si_iosize_max
)
403 pdev
->si_iosize_max
= dev
->si_iosize_max
;
405 error
= dev_dopen(dp
->d_rawdev
, oflags
, devtype
, td
);
409 * Inherit properties from the underlying device now that it is
417 error
= dsopen(dev
, devtype
, dp
->d_dsflags
, &dp
->d_slice
, &dp
->d_label
);
419 if (!dsisopen(dp
->d_slice
))
420 dev_dclose(dp
->d_rawdev
, oflags
, devtype
, td
);
422 dp
->d_flags
&= ~DISKFLAG_LOCK
;
423 if (dp
->d_flags
& DISKFLAG_WANTED
) {
424 dp
->d_flags
&= ~DISKFLAG_WANTED
;
432 * Close a disk device or partition
436 diskclose(dev_t dev
, int fflag
, int devtype
, struct thread
*td
)
444 dsclose(dev
, devtype
, dp
->d_slice
);
445 if (!dsisopen(dp
->d_slice
))
446 error
= dev_dclose(dp
->d_rawdev
, fflag
, devtype
, td
);
451 * Execute strategy routine
455 diskstrategy(dev_t dev
, struct bio
*bio
)
463 bio
->bio_buf
->b_error
= ENXIO
;
464 bio
->bio_buf
->b_flags
|= B_ERROR
;
468 KKASSERT(dev
->si_disk
== dp
);
471 * The dscheck() function will also transform the slice relative
472 * block number i.e. bio->bio_blkno into a block number that can be
473 * passed directly to the underlying raw device.
475 nbio
= dscheck(dev
, bio
, dp
->d_slice
);
480 dev_dstrategy(dp
->d_rawdev
, nbio
);
484 * First execute the ioctl on the disk device, and if it isn't supported
485 * try running it on the backing device.
489 diskioctl(dev_t dev
, u_long cmd
, caddr_t data
, int fflag
, struct thread
*td
)
498 error
= dsioctl(dev
, cmd
, data
, fflag
, &dp
->d_slice
);
499 if (error
== ENOIOCTL
)
500 error
= dev_dioctl(dp
->d_rawdev
, cmd
, data
, fflag
, td
);
516 return(dssize(dev
, &dp
->d_slice
));
518 if (dp
!= dev
->si_disk
) {
519 dev
->si_drv1
= pdev
->si_drv1
;
520 dev
->si_drv2
= pdev
->si_drv2
;
521 /* XXX: don't set bp->b_dev->si_disk (?) */
526 SYSCTL_INT(_debug_sizeof
, OID_AUTO
, disklabel
, CTLFLAG_RD
,
527 0, sizeof(struct disklabel
), "sizeof(struct disklabel)");
529 SYSCTL_INT(_debug_sizeof
, OID_AUTO
, diskslices
, CTLFLAG_RD
,
530 0, sizeof(struct diskslices
), "sizeof(struct diskslices)");
532 SYSCTL_INT(_debug_sizeof
, OID_AUTO
, disk
, CTLFLAG_RD
,
533 0, sizeof(struct disk
), "sizeof(struct disk)");
537 * Seek sort for disks.
539 * The bio_queue keep two queues, sorted in ascending block order. The first
540 * queue holds those requests which are positioned after the current block
541 * (in the first request); the second, which starts at queue->switch_point,
542 * holds requests which came in after their block number was passed. Thus
543 * we implement a one way scan, retracting after reaching the end of the drive
544 * to the first request on the second queue, at which time it becomes the
547 * A one-way scan is natural because of the way UNIX read-ahead blocks are
551 bioqdisksort(struct bio_queue_head
*bioq
, struct bio
*bio
)
557 be
= TAILQ_LAST(&bioq
->queue
, bio_queue
);
559 * If the queue is empty or we are an
560 * ordered transaction, then it's easy.
562 if ((bq
= bioq_first(bioq
)) == NULL
||
563 (bio
->bio_buf
->b_flags
& B_ORDERED
) != 0) {
564 bioq_insert_tail(bioq
, bio
);
566 } else if (bioq
->insert_point
!= NULL
) {
569 * A certain portion of the list is
570 * "locked" to preserve ordering, so
571 * we can only insert after the insert
574 bq
= bioq
->insert_point
;
578 * If we lie before the last removed (currently active)
579 * request, and are not inserting ourselves into the
580 * "locked" portion of the list, then we must add ourselves
581 * to the second request list.
583 if (bio
->bio_blkno
< bioq
->last_blkno
) {
585 bq
= bioq
->switch_point
;
587 * If we are starting a new secondary list,
591 bioq
->switch_point
= bio
;
592 bioq_insert_tail(bioq
, bio
);
596 * If we lie ahead of the current switch point,
597 * insert us before the switch point and move
600 if (bio
->bio_blkno
< bq
->bio_blkno
) {
601 bioq
->switch_point
= bio
;
602 TAILQ_INSERT_BEFORE(bq
, bio
, bio_act
);
606 if (bioq
->switch_point
!= NULL
)
607 be
= TAILQ_PREV(bioq
->switch_point
,
610 * If we lie between last_blkno and bq,
613 if (bio
->bio_blkno
< bq
->bio_blkno
) {
614 TAILQ_INSERT_BEFORE(bq
, bio
, bio_act
);
621 * Request is at/after our current position in the list.
622 * Optimize for sequential I/O by seeing if we go at the tail.
624 if (bio
->bio_blkno
> be
->bio_blkno
) {
625 TAILQ_INSERT_AFTER(&bioq
->queue
, be
, bio
, bio_act
);
629 /* Otherwise, insertion sort */
630 while ((bn
= TAILQ_NEXT(bq
, bio_act
)) != NULL
) {
633 * We want to go after the current request if it is the end
634 * of the first request list, or if the next request is a
635 * larger cylinder than our request.
637 if (bn
== bioq
->switch_point
638 || bio
->bio_blkno
< bn
->bio_blkno
)
642 TAILQ_INSERT_AFTER(&bioq
->queue
, bq
, bio
, bio_act
);
647 * Attempt to read a disk label from a device using the indicated strategy
648 * routine. The label must be partly set up before this: secpercyl, secsize
649 * and anything required in the strategy routine (e.g., dummy bounds for the
650 * partition containing the label) must be filled in before calling us.
651 * Returns NULL on success and an error string on failure.
654 readdisklabel(dev_t dev
, struct disklabel
*lp
)
657 struct disklabel
*dlp
;
660 bp
= geteblk((int)lp
->d_secsize
);
661 bp
->b_bio1
.bio_blkno
= LABELSECTOR
* ((int)lp
->d_secsize
/DEV_BSIZE
);
662 bp
->b_bcount
= lp
->d_secsize
;
663 bp
->b_flags
&= ~B_INVAL
;
664 bp
->b_flags
|= B_READ
;
665 dev_dstrategy(dev
, &bp
->b_bio1
);
668 else for (dlp
= (struct disklabel
*)bp
->b_data
;
669 dlp
<= (struct disklabel
*)((char *)bp
->b_data
+
670 lp
->d_secsize
- sizeof(*dlp
));
671 dlp
= (struct disklabel
*)((char *)dlp
+ sizeof(long))) {
672 if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
) {
674 msg
= "no disk label";
675 } else if (dlp
->d_npartitions
> MAXPARTITIONS
||
677 msg
= "disk label corrupted";
684 bp
->b_flags
|= B_INVAL
| B_AGE
;
690 * Check new disk label for sensibility before setting it.
693 setdisklabel(struct disklabel
*olp
, struct disklabel
*nlp
, u_long openmask
)
696 struct partition
*opp
, *npp
;
699 * Check it is actually a disklabel we are looking at.
701 if (nlp
->d_magic
!= DISKMAGIC
|| nlp
->d_magic2
!= DISKMAGIC
||
705 * For each partition that we think is open,
707 while ((i
= ffs((long)openmask
)) != 0) {
710 * Check it is not changing....
712 openmask
&= ~(1 << i
);
713 if (nlp
->d_npartitions
<= i
)
715 opp
= &olp
->d_partitions
[i
];
716 npp
= &nlp
->d_partitions
[i
];
717 if (npp
->p_offset
!= opp
->p_offset
|| npp
->p_size
< opp
->p_size
)
720 * Copy internally-set partition information
721 * if new label doesn't include it. XXX
722 * (If we are using it then we had better stay the same type)
723 * This is possibly dubious, as someone else noted (XXX)
725 if (npp
->p_fstype
== FS_UNUSED
&& opp
->p_fstype
!= FS_UNUSED
) {
726 npp
->p_fstype
= opp
->p_fstype
;
727 npp
->p_fsize
= opp
->p_fsize
;
728 npp
->p_frag
= opp
->p_frag
;
729 npp
->p_cpg
= opp
->p_cpg
;
733 nlp
->d_checksum
= dkcksum(nlp
);
739 * Write disk label back to device after modification.
742 writedisklabel(dev_t dev
, struct disklabel
*lp
)
745 struct disklabel
*dlp
;
748 if (lp
->d_partitions
[RAW_PART
].p_offset
!= 0)
749 return (EXDEV
); /* not quite right */
750 bp
= geteblk((int)lp
->d_secsize
);
751 bp
->b_bio1
.bio_blkno
= LABELSECTOR
* ((int)lp
->d_secsize
/DEV_BSIZE
);
752 bp
->b_bcount
= lp
->d_secsize
;
755 * We read the label first to see if it's there,
756 * in which case we will put ours at the same offset into the block..
757 * (I think this is stupid [Julian])
758 * Note that you can't write a label out over a corrupted label!
759 * (also stupid.. how do you write the first one? by raw writes?)
761 bp
->b_flags
&= ~B_INVAL
;
762 bp
->b_flags
|= B_READ
;
763 dev_dstrategy(dkmodpart(dev
, RAW_PART
), &bp
->b_bio1
);
767 for (dlp
= (struct disklabel
*)bp
->b_data
;
768 dlp
<= (struct disklabel
*)
769 ((char *)bp
->b_data
+ lp
->d_secsize
- sizeof(*dlp
));
770 dlp
= (struct disklabel
*)((char *)dlp
+ sizeof(long))) {
771 if (dlp
->d_magic
== DISKMAGIC
&& dlp
->d_magic2
== DISKMAGIC
&&
774 bp
->b_flags
&= ~(B_DONE
| B_READ
);
775 bp
->b_flags
|= B_WRITE
;
776 dev_dstrategy(dkmodpart(dev
, RAW_PART
), &bp
->b_bio1
);
784 bzero(bp
->b_data
, lp
->d_secsize
);
785 dlp
= (struct disklabel
*)bp
->b_data
;
787 bp
->b_flags
&= ~B_INVAL
;
788 bp
->b_flags
|= B_WRITE
;
792 bp
->b_flags
|= B_INVAL
| B_AGE
;
798 * Disk error is the preface to plaintive error messages
799 * about failing disk transfers. It prints messages of the form
801 hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d)
803 * if the offset of the error in the transfer and a disk label
804 * are both available. blkdone should be -1 if the position of the error
805 * is unknown; the disklabel pointer may be null from drivers that have not
806 * been converted to use them. The message is printed with printf
807 * if pri is LOG_PRINTF, otherwise it uses log at the specified priority.
808 * The message should be completed (with at least a newline) with printf
809 * or addlog, respectively. There is no trailing space.
812 diskerr(struct bio
*bio
, dev_t dev
, const char *what
, int pri
,
813 int blkdone
, struct disklabel
*lp
)
815 struct buf
*bp
= bio
->bio_buf
;
816 int unit
= dkunit(dev
);
817 int slice
= dkslice(dev
);
818 int part
= dkpart(dev
);
823 sname
= dsname(dev
, unit
, slice
, part
, partname
);
824 printf("%s%s: %s %sing fsbn ", sname
, partname
, what
,
825 bp
->b_flags
& B_READ
? "read" : "writ");
827 if (bp
->b_bcount
<= DEV_BSIZE
) {
828 printf("%ld", (long)sn
);
832 printf("%ld of ", (long)sn
);
834 printf("%ld-%ld", (long)bio
->bio_blkno
,
835 (long)(bio
->bio_blkno
+ (bp
->b_bcount
- 1) / DEV_BSIZE
));
837 if (lp
&& (blkdone
>= 0 || bp
->b_bcount
<= lp
->d_secsize
)) {
838 sn
+= lp
->d_partitions
[part
].p_offset
;
840 * XXX should add slice offset and not print the slice,
841 * but we don't know the slice pointer.
842 * XXX should print bio->bio_blkno so that this will work
843 * independent of slices, labels and bad sector remapping,
844 * but some drivers don't set bio->bio_blkno.
846 printf(" (%s bn %ld; cn %ld", sname
, (long)sn
,
847 (long)(sn
/ lp
->d_secpercyl
));
848 sn
%= (long)lp
->d_secpercyl
;
849 printf(" tn %ld sn %ld)", (long)(sn
/ lp
->d_nsectors
),
850 (long)(sn
% lp
->d_nsectors
));