1.\" 2.\" Copyright (c) 2009 Hudson River Trading LLC 3.\" Written by: John H. Baldwin <jhb@FreeBSD.org> 4.\" All rights reserved. 5.\" 6.\" Redistribution and use in source and binary forms, with or without 7.\" modification, are permitted provided that the following conditions 8.\" are met: 9.\" 1. Redistributions of source code must retain the above copyright 10.\" notice, this list of conditions and the following disclaimer. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice, this list of conditions and the following disclaimer in the 13.\" documentation and/or other materials provided with the distribution. 14.\" 15.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25.\" SUCH DAMAGE. 26.\" 27.Dd May 25, 2021 28.Dt SGLIST 9 29.Os 30.Sh NAME 31.Nm sglist , 32.Nm sglist_alloc , 33.Nm sglist_append , 34.Nm sglist_append_bio , 35.Nm sglist_append_mbuf , 36.Nm sglist_append_mbuf_epg , 37.Nm sglist_append_phys , 38.Nm sglist_append_sglist , 39.Nm sglist_append_single_mbuf , 40.Nm sglist_append_uio , 41.Nm sglist_append_user , 42.Nm sglist_append_vmpages , 43.Nm sglist_build , 44.Nm sglist_clone , 45.Nm sglist_consume_uio , 46.Nm sglist_count , 47.Nm sglist_count_mbuf_epg , 48.Nm sglist_count_vmpages , 49.Nm sglist_free , 50.Nm sglist_hold , 51.Nm sglist_init , 52.Nm sglist_join , 53.Nm sglist_length , 54.Nm sglist_reset , 55.Nm sglist_slice , 56.Nm sglist_split 57.Nd manage a scatter/gather list of physical memory addresses 58.Sh SYNOPSIS 59.In sys/types.h 60.In sys/sglist.h 61.Ft struct sglist * 62.Fn sglist_alloc "int nsegs" "int mflags" 63.Ft int 64.Fn sglist_append "struct sglist *sg" "void *buf" "size_t len" 65.Ft int 66.Fn sglist_append_bio "struct sglist *sg" "struct bio *bp" 67.Ft int 68.Fn sglist_append_mbuf_epg "struct sglist *sg" "struct mbuf *m" "size_t offset" "size_t len" 69.Ft int 70.Fn sglist_append_mbuf "struct sglist *sg" "struct mbuf *m" 71.Ft int 72.Fn sglist_append_phys "struct sglist *sg" "vm_paddr_t paddr" "size_t len" 73.Ft int 74.Fn sglist_append_sglist "struct sglist *sg" "struct sglist *source" "size_t offset" "size_t len" 75.Ft int 76.Fn sglist_append_single_mbuf "struct sglist *sg" "struct mbuf *m" 77.Ft int 78.Fn sglist_append_uio "struct sglist *sg" "struct uio *uio" 79.Ft int 80.Fn sglist_append_user "struct sglist *sg" "void *buf" "size_t len" "struct thread *td" 81.Ft int 82.Fn sglist_append_vmpages "struct sglist *sg" "vm_page_t *m" "size_t pgoff" "size_t len" 83.Ft struct sglist * 84.Fn sglist_build "void *buf" "size_t len" "int mflags" 85.Ft struct sglist * 86.Fn sglist_clone "struct sglist *sg" "int mflags" 87.Ft int 88.Fn sglist_consume_uio "struct sglist *sg" "struct uio *uio" "size_t resid" 89.Ft int 90.Fn sglist_count "void *buf" "size_t len" 91.Ft int 92.Fn sglist_count_mbuf_epg "struct mbuf *m" "size_t offset" "size_t len" 93.Ft int 94.Fn sglist_count_vmpages "vm_page_t *m" "size_t pgoff" "size_t len" 95.Ft void 96.Fn sglist_free "struct sglist *sg" 97.Ft struct sglist * 98.Fn sglist_hold "struct sglist *sg" 99.Ft void 100.Fn sglist_init "struct sglist *sg" "int maxsegs" "struct sglist_seg *segs" 101.Ft int 102.Fn sglist_join "struct sglist *first" "struct sglist *second" 103.Ft size_t 104.Fn sglist_length "struct sglist *sg" 105.Ft void 106.Fn sglist_reset "struct sglist *sg" 107.Ft int 108.Fn sglist_slice "struct sglist *original" "struct sglist **slice" "size_t offset" "size_t length" "int mflags" 109.Ft int 110.Fn sglist_split "struct sglist *original" "struct sglist **head" "size_t length" "int mflags" 111.Sh DESCRIPTION 112The 113.Nm 114API manages physical address ranges. 115Each list contains one or more elements. 116Each element contains a starting physical address and a length. 117Scatter/gather lists are read-only while they are shared. 118If one wishes to alter an existing scatter/gather list and does not hold the 119sole reference to the list, 120then one should create a new list instead of modifying the existing list. 121.Pp 122Each scatter/gather list object contains a reference count. 123New lists are created with a single reference. 124New references are obtained by calling 125.Nm sglist_hold 126and are released by calling 127.Nm sglist_free . 128.Ss Allocating and Initializing Lists 129Each 130.Nm 131object consists of a header structure and a variable-length array of 132scatter/gather list elements. 133The 134.Nm sglist_alloc 135function allocates a new list that contains a header and 136.Fa nsegs 137scatter/gather list elements. 138The 139.Fa mflags 140argument can be set to either 141.Dv M_NOWAIT 142or 143.Dv M_WAITOK . 144.Pp 145The 146.Nm sglist_count 147function returns the number of scatter/gather list elements needed to describe 148the physical address ranges mapped by a single kernel virtual address range. 149The kernel virtual address range starts at 150.Fa buf 151and is 152.Fa len 153bytes long. 154.Pp 155The 156.Nm sglist_count_mbuf_epg 157function returns the number of scatter/gather list elements needed to describe 158the external multipage mbuf buffer 159.Fa m . 160The ranges start at an offset of 161.Fa offset 162relative to the start of the buffer and is 163.Fa len 164bytes long. 165.Pp 166The 167.Nm sglist_count_vmpages 168function returns the number of scatter/gather list elements needed to describe 169the physical address ranges of a buffer backed by an array of virtual memory 170pages 171.Fa m . 172The buffer starts at an offset of 173.Fa pgoff 174bytes relative to the first page and is 175.Fa len 176bytes long. 177.Pp 178The 179.Nm sglist_build 180function allocates a new scatter/gather list object that describes the physical 181address ranges mapped by a single kernel virtual address range. 182The kernel virtual address range starts at 183.Fa buf 184and is 185.Fa len 186bytes long. 187The 188.Fa mflags 189argument can be set to either 190.Dv M_NOWAIT 191or 192.Dv M_WAITOK . 193.Pp 194The 195.Nm sglist_clone 196function returns a copy of an existing scatter/gather list object 197.Fa sg . 198The 199.Fa mflags 200argument can be set to either 201.Dv M_NOWAIT 202or 203.Dv M_WAITOK . 204This can be used to obtain a private copy of a scatter/gather list before 205modifying it. 206.Pp 207The 208.Nm sglist_init 209function initializes a scatter/gather list header. 210The header is pointed to by 211.Fa sg 212and is initialized to manage an array of 213.Fa maxsegs 214scatter/gather list elements pointed to by 215.Fa segs . 216This can be used to initialize a scatter/gather list header whose storage 217is not provided by 218.Nm sglist_alloc . 219In that case, the caller should not call 220.Nm sglist_free 221to release its own reference and is responsible for ensuring all other 222references to the list are dropped before it releases the storage for 223.Fa sg 224and 225.Fa segs . 226.Ss Constructing Scatter/Gather Lists 227The 228.Nm 229API provides several routines for building a scatter/gather list to describe 230one or more objects. 231Specifically, the 232.Nm sglist_append 233family of routines can be used to append the physical address ranges described 234by an object to the end of a scatter/gather list. 235All of these routines return 0 on success or an error on failure. 236If a request to append an address range to a scatter/gather list fails, 237the scatter/gather list will remain unchanged. 238.Pp 239The 240.Nm sglist_append 241function appends the physical address ranges described by a single kernel 242virtual address range to the scatter/gather list 243.Fa sg . 244The kernel virtual address range starts at 245.Fa buf 246and is 247.Fa len 248bytes long. 249.Pp 250The 251.Nm sglist_append_bio 252function appends the physical address ranges described by a single bio 253.Fa bp 254to the scatter/gather list 255.Fa sg . 256.Pp 257The 258.Nm sglist_append_mbuf_epg 259function appends the physical address ranges described by the 260external multipage 261.Xr mbuf 9 262buffer 263.Fa ext_pgs 264to the scatter/gather list 265.Fa sg . 266The physical address ranges start at offset 267.Fa offset 268within 269.Fa ext_pgs 270and continue for 271.Fa len 272bytes. 273Note that unlike 274.Nm sglist_append_mbuf , 275.Nm sglist_append_mbuf_epg 276only adds ranges for a single mbuf, 277not an entire mbuf chain. 278.Pp 279The 280.Nm sglist_append_mbuf 281function appends the physical address ranges described by an entire mbuf 282chain 283.Fa m 284to the scatter/gather list 285.Fa sg . 286.Pp 287The 288.Nm sglist_append_mbuf 289function appends the physical address ranges described by a single mbuf 290.Fa m 291to the scatter/gather list 292.Fa sg . 293.Pp 294The 295.Nm sglist_append_phys 296function appends a single physical address range to the scatter/gather list 297.Fa sg . 298The physical address range starts at 299.Fa paddr 300and is 301.Fa len 302bytes long. 303.Pp 304The 305.Nm sglist_append_sglist 306function appends physical address ranges described by the scatter/gather list 307.Fa source 308to the scatter/gather list 309.Fa sg . 310The physical address ranges start at offset 311.Fa offset 312within 313.Fa source 314and continue for 315.Fa len 316bytes. 317.Pp 318The 319.Nm sglist_append_uio 320function appends the physical address ranges described by a 321.Xr uio 9 322object to the scatter/gather list 323.Fa sg . 324Note that it is the caller's responsibility to ensure that the pages backing 325the I/O request are wired for the lifetime of 326.Fa sg . 327Note also that this routine does not modify 328.Fa uio . 329.Pp 330The 331.Nm sglist_append_user 332function appends the physical address ranges described by a single user 333virtual address range to the scatter/gather list 334.Fa sg . 335The user virtual address range is relative to the address space of the thread 336.Fa td . 337It starts at 338.Fa buf 339and is 340.Fa len 341bytes long. 342Note that it is the caller's responsibility to ensure that the pages backing 343the user buffer are wired for the lifetime of 344.Fa sg . 345.Pp 346The 347.Nm sglist_append_vmpages 348function appends the physical address ranges of a buffer backed by an array 349of virtual memory pages 350.Fa m . 351The buffer starts at an offset of 352.Fa pgoff 353bytes relative to the first page and is 354.Fa len 355bytes long. 356.Pp 357The 358.Nm sglist_consume_uio 359function is a variation of 360.Nm sglist_append_uio . 361As with 362.Nm sglist_append_uio , 363it appends the physical address ranges described by 364.Fa uio 365to the scatter/gather list 366.Fa sg . 367Unlike 368.Nm sglist_append_uio , 369however, 370.Nm sglist_consume_uio 371modifies the I/O request to indicate that the appended address ranges have 372been processed similar to calling 373.Xr uiomove 9 . 374This routine will only append ranges that describe up to 375.Fa resid 376total bytes in length. 377If the available segments in the scatter/gather list are exhausted before 378.Fa resid 379bytes are processed, 380then the 381.Fa uio 382structure will be updated to reflect the actual number of bytes processed, 383and 384.Nm sglist_consume_io 385will return zero to indicate success. 386In effect, this function will perform partial reads or writes. 387The caller can compare the 388.Fa uio_resid 389member of 390.Fa uio 391before and after calling 392.Nm sglist_consume_uio 393to determine the actual number of bytes processed. 394.Ss Manipulating Scatter/Gather Lists 395The 396.Nm sglist_join 397function appends physical address ranges from the scatter/gather list 398.Fa second 399onto 400.Fa first 401and then resets 402.Fa second 403to an empty list. 404It returns zero on success or an error on failure. 405.Pp 406The 407.Nm sglist_split 408function splits an existing scatter/gather list into two lists. 409The first 410.Fa length 411bytes described by the list 412.Fa original 413are moved to a new list 414.Fa *head . 415If 416.Fa original 417describes a total address range that is smaller than 418.Fa length 419bytes, 420then all of the address ranges will be moved to the new list at 421.Fa *head 422and 423.Fa original 424will be an empty list. 425The caller may supply an existing scatter/gather list in 426.Fa *head . 427If so, the list must be empty. 428Otherwise, the caller may set 429.Fa *head 430to 431.Dv NULL 432in which case a new scatter/gather list will be allocated. 433In that case, 434.Fa mflags 435may be set to either 436.Dv M_NOWAIT 437or 438.Dv M_WAITOK . 439Note that since the 440.Fa original 441list is modified by this call, it must be a private list with no other 442references. 443The 444.Nm sglist_split 445function returns zero on success or an error on failure. 446.Pp 447The 448.Nm sglist_slice 449function generates a new scatter/gather list from a sub-range of an existing 450scatter/gather list 451.Fa original . 452The sub-range to extract is specified by the 453.Fa offset 454and 455.Fa length 456parameters. 457The new scatter/gather list is stored in 458.Fa *slice . 459As with 460.Fa head 461for 462.Nm sglist_join , 463the caller may either provide an empty scatter/gather list, 464or it may set 465.Fa *slice 466to 467.Dv NULL 468in which case 469.Nm sglist_slice 470will allocate a new list subject to 471.Fa mflags . 472Unlike 473.Nm sglist_split , 474.Nm sglist_slice 475does not modify 476.Fa original 477and does not require it to be a private list. 478The 479.Nm sglist_split 480function returns zero on success or an error on failure. 481.Ss Miscellaneous Routines 482The 483.Nm sglist_reset 484function clears the scatter/gather list 485.Fa sg 486so that it no longer maps any address ranges. 487This can allow reuse of a single scatter/gather list object for multiple 488requests. 489.Pp 490The 491.Nm sglist_length 492function returns the total length of the physical address ranges described 493by the scatter/gather list 494.Fa sg . 495.Sh RETURN VALUES 496The 497.Nm sglist_alloc , 498.Nm sglist_build , 499and 500.Nm sglist_clone 501functions return a new scatter/gather list on success or 502.Dv NULL 503on failure. 504.Pp 505The 506.Nm sglist_append 507family of functions and the 508.Nm sglist_consume_uio , 509.Nm sglist_join , 510.Nm sglist_slice , 511and 512.Nm sglist_split 513functions return zero on success or an error on failure. 514.Pp 515The 516.Nm sglist_count 517family of 518functions return a count of scatter/gather list elements. 519.Pp 520The 521.Nm sglist_length 522function returns a count of address space described by a scatter/gather list 523in bytes. 524.Sh ERRORS 525The 526.Nm sglist_append 527functions return the following errors on failure: 528.Bl -tag -width Er 529.It Bq Er EINVAL 530The scatter/gather list has zero segments. 531.It Bq Er EFBIG 532There are not enough available segments in the scatter/gather list to append 533the specified physical address ranges. 534.El 535.Pp 536The 537.Nm sglist_consume_uio 538function returns the following error on failure: 539.Bl -tag -width Er 540.It Bq Er EINVAL 541The scatter/gather list has zero segments. 542.El 543.Pp 544The 545.Nm sglist_join 546function returns the following error on failure: 547.Bl -tag -width Er 548.It Bq Er EFBIG 549There are not enough available segments in the scatter/gather list 550.Fa first 551to append the physical address ranges from 552.Fa second . 553.El 554.Pp 555The 556.Nm sglist_slice 557function returns the following errors on failure: 558.Bl -tag -width Er 559.It Bq Er EINVAL 560The 561.Fa original 562scatter/gather list does not describe enough address space to cover the 563requested sub-range. 564.It Bq Er EINVAL 565The caller-supplied scatter/gather list in 566.Fa *slice 567is not empty. 568.It Bq Er ENOMEM 569An attempt to allocate a new scatter/gather list with 570.Dv M_NOWAIT 571set in 572.Fa mflags 573failed. 574.It Bq Er EFBIG 575There are not enough available segments in the caller-supplied scatter/gather 576list in 577.Fa *slice 578to describe the requested physical address ranges. 579.El 580.Pp 581The 582.Nm sglist_split 583function returns the following errors on failure: 584.Bl -tag -width Er 585.It Bq Er EDOOFUS 586The 587.Fa original 588scatter/gather list has more than one reference. 589.It Bq Er EINVAL 590The caller-supplied scatter/gather list in 591.Fa *head 592is not empty. 593.It Bq Er ENOMEM 594An attempt to allocate a new scatter/gather list with 595.Dv M_NOWAIT 596set in 597.Fa mflags 598failed. 599.It Bq Er EFBIG 600There are not enough available segments in the caller-supplied scatter/gather 601list in 602.Fa *head 603to describe the requested physical address ranges. 604.El 605.Sh SEE ALSO 606.Xr g_bio 9 , 607.Xr malloc 9 , 608.Xr mbuf 9 , 609.Xr uio 9 610.Sh HISTORY 611This API was first introduced in 612.Fx 8.0 . 613