1.\" $OpenBSD: disk.9,v 1.33 2013/07/17 20:21:52 schwarze Exp $ 2.\" $NetBSD: disk.9,v 1.2 1996/04/08 20:41:25 jtc Exp $ 3.\" 4.\" Copyright (c) 1995, 1996 Jason R. Thorpe. 5.\" All rights reserved. 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 1. Redistributions of source code must retain the above copyright 11.\" notice, this list of conditions and the following disclaimer. 12.\" 2. Redistributions in binary form must reproduce the above copyright 13.\" notice, this list of conditions and the following disclaimer in the 14.\" documentation and/or other materials provided with the distribution. 15.\" 3. All advertising materials mentioning features or use of this software 16.\" must display the following acknowledgement: 17.\" This product includes software developed for the NetBSD Project 18.\" by Jason R. Thorpe. 19.\" 4. The name of the author may not be used to endorse or promote products 20.\" derived from this software without specific prior written permission. 21.\" 22.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25.\" IN NO EVENT SHALL THE AUTHOR 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 31.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32.\" SUCH DAMAGE. 33.\" 34.Dd $Mdocdate: July 17 2013 $ 35.Dt DISK 9 36.Os 37.Sh NAME 38.Nm disk 39.Nd generic disk framework 40.Sh SYNOPSIS 41.In sys/types.h 42.In sys/disklabel.h 43.In sys/disk.h 44.Ft void 45.Fn disk_init "void" 46.Ft void 47.Fn disk_attach "struct disk *" 48.Ft void 49.Fn disk_detach "struct disk *" 50.Ft void 51.Fn disk_busy "struct disk *" 52.Ft void 53.Fn disk_unbusy "struct disk *" "long bcount" "int read" 54.Sh DESCRIPTION 55The 56.Ox 57generic disk framework is designed to provide flexible, 58scalable, and consistent handling of disk state and metrics information. 59The fundamental component of this framework is the 60.Nm 61structure, which is defined as follows: 62.Bd -literal 63struct disk { 64 TAILQ_ENTRY(disk) dk_link; /* link in global disklist */ 65 struct rwlock dk_lock; /* disk lock */ 66 struct mutex dk_mtx; /* busy/unbusy mtx */ 67 char *dk_name; /* disk name */ 68 struct device *dk_device; /* disk device structure. */ 69 dev_t dk_devno; /* disk device number. */ 70 int dk_flags; /* disk flags */ 71#define DKF_CONSTRUCTED 0x0001 72#define DKF_OPENED 0x0002 73#define DKF_NOLABELREAD 0x0004 74 75 /* 76 * Metrics data; note that some metrics may have no meaning 77 * on certain types of disks. 78 */ 79 int dk_busy; /* busy counter */ 80 u_int64_t dk_rxfer; /* total number of read transfers */ 81 u_int64_t dk_wxfer; /* total number of write transfers */ 82 u_int64_t dk_seek; /* total independent seek operations */ 83 u_int64_t dk_rbytes; /* total bytes read */ 84 u_int64_t dk_wbytes; /* total bytes written */ 85 struct timeval dk_attachtime; /* time disk was attached */ 86 struct timeval dk_timestamp; /*time of first busy or any unbusy*/ 87 struct timeval dk_time; /* total time spent busy */ 88 89 int dk_bopenmask; /* block devices open */ 90 int dk_copenmask; /* character devices open */ 91 int dk_openmask; /* composite (bopen|copen) */ 92 int dk_state; /* label state ### */ 93 int dk_blkshift; /*shift to convert DEV_BSIZE to blks*/ 94 int dk_byteshift; /* shift to convert bytes to blks */ 95 96 /* 97 * Disk label information. Storage for the in-core disk label 98 * must be dynamically allocated, otherwise the size of this 99 * structure becomes machine-dependent. 100 */ 101 struct disklabel *dk_label; 102}; 103.Ed 104.Pp 105The system maintains a global linked-list of all disks attached to the 106system. 107This list, called 108.Nm disklist , 109may grow or shrink over time as disks are dynamically added and removed 110from the system. 111An example of a driver which currently makes use of the detachment 112capability of the framework is the 113.Xr vnd 4 114pseudo-device driver. 115.Pp 116The following is a brief description of each function in the framework: 117.Bl -tag -width "disk_unbusy()" 118.It Fn disk_init 119Initialize the disklist and other data structures used by the framework. 120Called by 121.Fn main 122before autoconfiguration. 123.It Fn disk_attach 124Attach a disk; allocate storage for the disklabel, set the 125.Dq attached time 126timestamp, insert the disk into the disklist, and increment the 127system disk count. 128.It Fn disk_detach 129Detach a disk; free storage for the disklabel, remove the disk 130from the disklist, and decrement the system disk count. 131If the count drops below zero, panic. 132.It Fn disk_busy 133Increment the disk's 134.Dq busy counter . 135If this counter goes from 0 to 1, set the timestamp corresponding to 136this transfer. 137.It Fn disk_unbusy 138Decrement a disk's busy counter. 139If the count drops below zero, print a warning message. 140Get the current time, subtract it from the disk's timestamp, and add 141the difference to the disk's running total. 142Set the disk's timestamp to the current time. 143If the provided byte count is greater than 0, 144add it to the disk's running total and increment the number of transfers 145performed by the disk. 146The third argument 147.Ar read 148specifies the direction of I/O; 149if non-zero it means reading from the disk, 150otherwise it means writing to the disk. 151.El 152.Pp 153The functions typically called by device drivers are 154.Fn disk_attach , 155.Fn disk_detach , 156.Fn disk_busy 157and 158.Fn disk_unbusy . 159.Sh USING THE FRAMEWORK 160This section includes a description on basic use of the framework 161and example usage of its functions. 162Actual implementation of 163a device driver which utilizes the framework may vary. 164.Pp 165A special routine, 166.Fn disk_init , 167is provided to perform basic initialization of data structures used by 168the framework. 169It is called exactly once by the system, in 170.Fn main , 171before device autoconfiguration. 172.Pp 173Each device in the system uses a 174.Dq softc 175structure which contains autoconfiguration and state information for that 176device. 177In the case of disks, the softc should also contain one instance 178of the disk structure, e.g.: 179.Bd -literal 180struct foo_softc { 181 struct device *sc_dev; /* generic device information */ 182 struct disk *sc_dk; /* generic disk information */ 183 [ . . . more . . . ] 184}; 185.Ed 186.Pp 187In order for the system to gather metrics data about a disk, the disk must 188be registered with the system. 189The 190.Fn disk_attach 191routine performs all of the functions currently required to register a disk 192with the system including allocation of disklabel storage space, 193recording of the time since boot that the disk was attached, and insertion 194into the disklist. 195Note that since this function allocates storage space 196for the disklabel, it must be called before the disklabel is read from the 197media or used in any other way. 198Before 199.Fn disk_attach 200is called, a portion of the disk structure must be initialized with 201data specific to that disk. 202For example, in the 203.Dq foo 204disk driver, the following would be performed in the autoconfiguration 205.Dq attach 206routine: 207.Bd -literal 208void 209fooattach(parent, self, aux) 210 struct device *parent, *self; 211 void *aux; 212{ 213 struct foo_softc *sc = (struct foo_softc *)self; 214 [ . . . ] 215 216 /* Initialize and attach the disk structure. */ 217 sc->sc_dk.dk_driver = &foodkdriver; 218 sc->sc_dk.dk_name = sc->sc_dev.dv_xname; 219 disk_attach(&sc->sc_dk); 220 221 /* Read geometry and fill in pertinent parts of disklabel. */ 222 [ . . . ] 223} 224.Ed 225.Pp 226The 227.Nm foodkdriver 228above is the disk's 229.Dq driver 230switch. 231This switch currently includes a pointer to the disk's 232.Dq strategy 233routine. 234This switch needs to have global scope and should be initialized as follows: 235.Bd -literal 236void foostrategy(struct buf *); 237struct dkdriver foodkdriver = { foostrategy }; 238.Ed 239.Pp 240Once the disk is attached, metrics may be gathered on that disk. 241In order to gather metrics data, the driver must tell the framework 242when the disk starts and stops operations. 243This functionality is provided by the 244.Fn disk_busy 245and 246.Fn disk_unbusy 247routines. 248The 249.Fn disk_busy 250routine should be called immediately before a command to the disk is 251sent, e.g.: 252.Bd -literal 253void 254foostart(sc) 255 struct foo_softc *sc; 256{ 257 [ . . . ] 258 259 /* Get buffer from drive's transfer queue. */ 260 [ . . . ] 261 262 /* Build command to send to drive. */ 263 [ . . . ] 264 265 /* Tell the disk framework we're going busy. */ 266 disk_busy(&sc->sc_dk); 267 268 /* Send command to the drive. */ 269 [ . . . ] 270} 271.Ed 272.Pp 273When 274.Fn disk_busy 275is called, a timestamp is taken if the disk's busy counter moves from 2760 to 1, indicating the disk has gone from an idle to non-idle state. 277Note that 278.Fn disk_busy 279must be called at 280.Fn splbio . 281At the end of a transaction, the 282.Fn disk_unbusy 283routine should be called. 284This routine performs some consistency checks, 285such as ensuring that the calls to 286.Fn disk_busy 287and 288.Fn disk_unbusy 289are balanced. 290This routine also performs the actual metrics calculation. 291A timestamp is taken, and the difference from the timestamp taken in 292.Fn disk_busy 293is added to the disk's total running time. 294The disk's timestamp is then 295updated in case there is more than one pending transfer on the disk. 296A byte count is also added to the disk's running total, and if greater than 297zero, the number of transfers the disk has performed is incremented. 298.Bd -literal 299void 300foodone(xfer) 301 struct foo_xfer *xfer; 302{ 303 struct foo_softc = (struct foo_softc *)xfer->xf_softc; 304 struct buf *bp = xfer->xf_buf; 305 long nbytes; 306 [ . . . ] 307 308 /* 309 * Get number of bytes transferred. If there is no buf 310 * associated with the xfer, we are being called at the 311 * end of a non-I/O command. 312 */ 313 if (bp == NULL) 314 nbytes = 0; 315 else 316 nbytes = bp->b_bcount - bp->b_resid; 317 318 [ . . . ] 319 320 /* Notify the disk framework that we've completed the transfer. */ 321 disk_unbusy(&sc->sc_dk, nbytes); 322 323 [ . . . ] 324} 325.Ed 326.Pp 327Like 328.Fn disk_busy , 329.Fn disk_unbusy 330must be called at 331.Fn splbio . 332.Sh CODE REFERENCES 333The disk framework itself is implemented within the file 334.Pa sys/kern/subr_disk.c . 335Data structures and function prototypes for the framework are located in 336.Pa sys/sys/disk.h . 337.Pp 338The 339.Ox 340machine-independent SCSI disk and CD-ROM drivers utilize the disk framework. 341They are located in 342.Pa sys/scsi/sd.c 343and 344.Pa sys/scsi/cd.c . 345.Pp 346The 347.Ox 348.Xr vnd 4 349driver utilizes the detachment capability of the framework. 350This is located in 351.Pa sys/dev/vnd.c . 352.Sh SEE ALSO 353.Xr vnd 4 , 354.Xr spl 9 355.Sh HISTORY 356The 357.Ox 358generic disk framework first appeared in 359.Nx 1.2 . 360.Sh AUTHORS 361The 362.Ox 363generic disk framework was architected and implemented within 364.Nx 365by 366.An Jason R. Thorpe Aq Mt thorpej@NetBSD.ORG . 367