17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
229093SRamana.Srikanth@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM #include <sys/types.h>
277836SJohn.Forte@Sun.COM #include <sys/param.h>
287836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
297836SJohn.Forte@Sun.COM #include <sys/kmem.h>
307836SJohn.Forte@Sun.COM #include <sys/stat.h>
317836SJohn.Forte@Sun.COM #include <sys/buf.h>
327836SJohn.Forte@Sun.COM #include <sys/open.h>
337836SJohn.Forte@Sun.COM #include <sys/conf.h>
347836SJohn.Forte@Sun.COM #include <sys/file.h>
357836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
367836SJohn.Forte@Sun.COM #include <sys/errno.h>
377836SJohn.Forte@Sun.COM #include <sys/ddi.h>
387836SJohn.Forte@Sun.COM
397836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
407836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
417836SJohn.Forte@Sun.COM
427836SJohn.Forte@Sun.COM #include <sys/sdt.h> /* dtrace is S10 or later */
437836SJohn.Forte@Sun.COM
44*11185SSean.McEnroe@Sun.COM #include <vm/seg_kmem.h>
457836SJohn.Forte@Sun.COM #include "sd_bcache.h"
467836SJohn.Forte@Sun.COM #include "sd_trace.h"
477836SJohn.Forte@Sun.COM #include "sd_io.h"
487836SJohn.Forte@Sun.COM #include "sd_iob.h"
497836SJohn.Forte@Sun.COM #include "sd_misc.h"
507836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG) /* simulate disk errors */
517836SJohn.Forte@Sun.COM #include "sd_tdaemon.h"
527836SJohn.Forte@Sun.COM #endif
537836SJohn.Forte@Sun.COM
547836SJohn.Forte@Sun.COM #ifndef DS_DDICT
557836SJohn.Forte@Sun.COM extern uintptr_t kobj_getsymvalue(char *, int); /* DDI violation */
567836SJohn.Forte@Sun.COM #endif
577836SJohn.Forte@Sun.COM
587836SJohn.Forte@Sun.COM #define DO_PAGE_LIST sdbc_do_page /* enable pagelist code */
597836SJohn.Forte@Sun.COM
607836SJohn.Forte@Sun.COM int sdbc_do_page = 0;
617836SJohn.Forte@Sun.COM
627836SJohn.Forte@Sun.COM #define SGIO_MAX 254
637836SJohn.Forte@Sun.COM
647836SJohn.Forte@Sun.COM static kmutex_t sdbc_bio_mutex;
657836SJohn.Forte@Sun.COM static int sdbc_bio_count;
667836SJohn.Forte@Sun.COM
677836SJohn.Forte@Sun.COM static unsigned long page_size, page_offset_mask;
687836SJohn.Forte@Sun.COM
697836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
707836SJohn.Forte@Sun.COM static __start_io_count = 0;
717836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
727836SJohn.Forte@Sun.COM
737836SJohn.Forte@Sun.COM /*
747836SJohn.Forte@Sun.COM * Forward declare all statics that are used before defined to enforce
757836SJohn.Forte@Sun.COM * parameter checking. Also forward-declare all functions that have 64-bit
767836SJohn.Forte@Sun.COM * argument types to enforce correct parameter checking.
777836SJohn.Forte@Sun.COM *
787836SJohn.Forte@Sun.COM * Some (if not all) of these could be removed if the code were reordered
797836SJohn.Forte@Sun.COM */
807836SJohn.Forte@Sun.COM
817836SJohn.Forte@Sun.COM static int _sd_sync_ea(struct buf *, iob_hook_t *);
827836SJohn.Forte@Sun.COM static int _sd_async_ea(struct buf *, iob_hook_t *);
837836SJohn.Forte@Sun.COM static void _sd_pack_pages(struct buf *bp, struct buf *list, sd_addr_t *addr,
847836SJohn.Forte@Sun.COM nsc_off_t offset, nsc_size_t size);
857836SJohn.Forte@Sun.COM static void _sd_pack_pages_nopageio(struct buf *bp, struct buf *list,
867836SJohn.Forte@Sun.COM sd_addr_t *addr, nsc_off_t offset, nsc_size_t size);
877836SJohn.Forte@Sun.COM static void _sd_setup_iob(struct buf *bp, dev_t dev, nsc_off_t pos, int flag);
887836SJohn.Forte@Sun.COM
897836SJohn.Forte@Sun.COM #ifdef DEBUG
907836SJohn.Forte@Sun.COM static int _sdbc_ioj_lookup(dev_t);
917836SJohn.Forte@Sun.COM static void _sdbc_ioj_clear_err(int);
927836SJohn.Forte@Sun.COM #endif
937836SJohn.Forte@Sun.COM
947836SJohn.Forte@Sun.COM static int SD_WRITES_TOT = 0;
957836SJohn.Forte@Sun.COM static int SD_WRITES_LEN[100];
967836SJohn.Forte@Sun.COM
977836SJohn.Forte@Sun.COM _sd_buf_list_t _sd_buflist;
987836SJohn.Forte@Sun.COM
997836SJohn.Forte@Sun.COM /*
1007836SJohn.Forte@Sun.COM * _sd_add_vm_to_bp_plist - add the page corresponding to the
1017836SJohn.Forte@Sun.COM * virtual address "v" (kernel virtaddr) to the pagelist linked
1027836SJohn.Forte@Sun.COM * to buffer "bp".
1037836SJohn.Forte@Sun.COM *
1047836SJohn.Forte@Sun.COM * The virtual address "v" is "known" to be allocated by segkmem
1057836SJohn.Forte@Sun.COM * and we can look up the page by using the segkmem vnode kvp.
1067836SJohn.Forte@Sun.COM * This violates the ddi/ddk but is workable for now anyway.
1077836SJohn.Forte@Sun.COM *
1087836SJohn.Forte@Sun.COM *
1097836SJohn.Forte@Sun.COM */
1107836SJohn.Forte@Sun.COM static void
_sd_add_vm_to_bp_plist(struct buf * bp,unsigned char * v)1117836SJohn.Forte@Sun.COM _sd_add_vm_to_bp_plist(struct buf *bp, unsigned char *v)
1127836SJohn.Forte@Sun.COM {
1137836SJohn.Forte@Sun.COM page_t *pp;
1147836SJohn.Forte@Sun.COM page_t *one_pg = NULL;
1157836SJohn.Forte@Sun.COM
1167836SJohn.Forte@Sun.COM pp = page_find(&kvp, (u_offset_t)((uintptr_t)v & ~page_offset_mask));
1177836SJohn.Forte@Sun.COM if (!pp) {
1187836SJohn.Forte@Sun.COM cmn_err(CE_PANIC,
1197836SJohn.Forte@Sun.COM "_sd_add_vm_to_bp_plist: couldn't find page for 0x%p",
1207836SJohn.Forte@Sun.COM (void *)v);
1217836SJohn.Forte@Sun.COM }
1227836SJohn.Forte@Sun.COM
1237836SJohn.Forte@Sun.COM page_add(&one_pg, pp);
1247836SJohn.Forte@Sun.COM page_list_concat(&(bp->b_pages), &one_pg);
1257836SJohn.Forte@Sun.COM
1267836SJohn.Forte@Sun.COM }
1277836SJohn.Forte@Sun.COM
1287836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
1297836SJohn.Forte@Sun.COM static int
_sd_count_pages(page_t * pp)1307836SJohn.Forte@Sun.COM _sd_count_pages(page_t *pp)
1317836SJohn.Forte@Sun.COM {
1327836SJohn.Forte@Sun.COM int cnt = 0;
1337836SJohn.Forte@Sun.COM page_t *pp1;
1347836SJohn.Forte@Sun.COM if (pp == NULL)
1357836SJohn.Forte@Sun.COM return (cnt);
1367836SJohn.Forte@Sun.COM
1377836SJohn.Forte@Sun.COM for (cnt = 1, pp1 = pp->p_next; pp != pp1; cnt++, pp1 = pp1->p_next)
1387836SJohn.Forte@Sun.COM ;
1397836SJohn.Forte@Sun.COM
1407836SJohn.Forte@Sun.COM return (cnt);
1417836SJohn.Forte@Sun.COM }
1427836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
1437836SJohn.Forte@Sun.COM
1447836SJohn.Forte@Sun.COM
1457836SJohn.Forte@Sun.COM /*
1467836SJohn.Forte@Sun.COM * _sdbc_iobuf_load - load time initialization of io bufs structures.
1477836SJohn.Forte@Sun.COM *
1487836SJohn.Forte@Sun.COM *
1497836SJohn.Forte@Sun.COM * RETURNS:
1507836SJohn.Forte@Sun.COM * 0 - success.
1517836SJohn.Forte@Sun.COM * -1 - failure.
1527836SJohn.Forte@Sun.COM *
1537836SJohn.Forte@Sun.COM * USAGE:
1547836SJohn.Forte@Sun.COM * This routine initializes load time buf structures.
1557836SJohn.Forte@Sun.COM * Should be called when the cache is loaded.
1567836SJohn.Forte@Sun.COM */
1577836SJohn.Forte@Sun.COM
1587836SJohn.Forte@Sun.COM int
_sdbc_iobuf_load(void)1597836SJohn.Forte@Sun.COM _sdbc_iobuf_load(void)
1607836SJohn.Forte@Sun.COM {
1617836SJohn.Forte@Sun.COM mutex_init(&sdbc_bio_mutex, NULL, MUTEX_DRIVER, NULL);
1627836SJohn.Forte@Sun.COM
1637836SJohn.Forte@Sun.COM /*
1647836SJohn.Forte@Sun.COM * HACK add a ref to kvp, to prevent VN_RELE on it from panicing
1657836SJohn.Forte@Sun.COM * the system
1667836SJohn.Forte@Sun.COM */
1677836SJohn.Forte@Sun.COM VN_HOLD(&kvp);
1687836SJohn.Forte@Sun.COM
1697836SJohn.Forte@Sun.COM return (0);
1707836SJohn.Forte@Sun.COM }
1717836SJohn.Forte@Sun.COM
1727836SJohn.Forte@Sun.COM /*
1737836SJohn.Forte@Sun.COM * _sdbc_iobuf_unload - unload time cleanup of io buf structures.
1747836SJohn.Forte@Sun.COM *
1757836SJohn.Forte@Sun.COM *
1767836SJohn.Forte@Sun.COM * USAGE:
1777836SJohn.Forte@Sun.COM * This routine removes load time buf structures.
1787836SJohn.Forte@Sun.COM * Should be called when the cache is unloaded.
1797836SJohn.Forte@Sun.COM */
1807836SJohn.Forte@Sun.COM void
_sdbc_iobuf_unload(void)1817836SJohn.Forte@Sun.COM _sdbc_iobuf_unload(void)
1827836SJohn.Forte@Sun.COM {
1837836SJohn.Forte@Sun.COM /* Undo our VN_HOLD hack, by putting ref count back to normal state */
1847836SJohn.Forte@Sun.COM mutex_enter(&kvp.v_lock);
1857836SJohn.Forte@Sun.COM kvp.v_count = 0;
1867836SJohn.Forte@Sun.COM mutex_exit(&kvp.v_lock);
1877836SJohn.Forte@Sun.COM
1887836SJohn.Forte@Sun.COM mutex_destroy(&sdbc_bio_mutex);
1897836SJohn.Forte@Sun.COM bzero(&_sd_buflist, sizeof (_sd_buf_list_t));
1907836SJohn.Forte@Sun.COM }
1917836SJohn.Forte@Sun.COM
1927836SJohn.Forte@Sun.COM /*
1937836SJohn.Forte@Sun.COM * _sdbc_iobuf_configure - configure a list of io bufs for later use.
1947836SJohn.Forte@Sun.COM *
1957836SJohn.Forte@Sun.COM * ARGUMENTS:
1967836SJohn.Forte@Sun.COM * num_bufs - number of buffers. (from the configuration file)
1977836SJohn.Forte@Sun.COM *
1987836SJohn.Forte@Sun.COM * RETURNS:
1997836SJohn.Forte@Sun.COM * 0 - success.
2007836SJohn.Forte@Sun.COM * <0 - failure.
2017836SJohn.Forte@Sun.COM *
2027836SJohn.Forte@Sun.COM * USAGE:
2037836SJohn.Forte@Sun.COM * This routine configures the buf structures for io.
2047836SJohn.Forte@Sun.COM * Should be called when the cache is configured.
2057836SJohn.Forte@Sun.COM */
2067836SJohn.Forte@Sun.COM
2077836SJohn.Forte@Sun.COM int
_sdbc_iobuf_configure(int num)2087836SJohn.Forte@Sun.COM _sdbc_iobuf_configure(int num)
2097836SJohn.Forte@Sun.COM {
2107836SJohn.Forte@Sun.COM int i;
2117836SJohn.Forte@Sun.COM _sd_buf_list_t *buflist;
2127836SJohn.Forte@Sun.COM iob_hook_t *hook;
2137836SJohn.Forte@Sun.COM char symbol_name[32];
2147836SJohn.Forte@Sun.COM
2157836SJohn.Forte@Sun.COM if (!num || (num > _SD_DEFAULT_IOBUFS))
2167836SJohn.Forte@Sun.COM num = _SD_DEFAULT_IOBUFS;
2177836SJohn.Forte@Sun.COM
2187836SJohn.Forte@Sun.COM if ((_sd_buflist.hooks = (iob_hook_t *)nsc_kmem_zalloc(
2199093SRamana.Srikanth@Sun.COM num * sizeof (iob_hook_t), KM_SLEEP, sdbc_iobuf_mem)) == NULL) {
2207836SJohn.Forte@Sun.COM return (-1);
2217836SJohn.Forte@Sun.COM }
2227836SJohn.Forte@Sun.COM
2237836SJohn.Forte@Sun.COM buflist = &_sd_buflist;
2247836SJohn.Forte@Sun.COM buflist->bl_init_count = num;
2257836SJohn.Forte@Sun.COM buflist->bl_hooks_avail = num;
2267836SJohn.Forte@Sun.COM buflist->bl_hook_lowmark = num;
2277836SJohn.Forte@Sun.COM hook = buflist->hooks;
2287836SJohn.Forte@Sun.COM buflist->hook_head = hook;
2297836SJohn.Forte@Sun.COM for (i = 0; i < num; i++, hook++) {
2307836SJohn.Forte@Sun.COM cv_init(&hook->wait, NULL, CV_DRIVER, NULL);
2317836SJohn.Forte@Sun.COM (void) sprintf(symbol_name, "sd_iob_dcb%d", i);
2327836SJohn.Forte@Sun.COM hook->iob_drv_iodone = (dcb_t)kobj_getsymvalue(symbol_name, 0);
2337836SJohn.Forte@Sun.COM if (!hook->iob_drv_iodone) {
2347836SJohn.Forte@Sun.COM return (-2);
2357836SJohn.Forte@Sun.COM }
2367836SJohn.Forte@Sun.COM hook->next_hook = hook+1;
2377836SJohn.Forte@Sun.COM }
2387836SJohn.Forte@Sun.COM (hook-1)->next_hook = NULL;
2397836SJohn.Forte@Sun.COM
2407836SJohn.Forte@Sun.COM for (i = 0; i < MAX_HOOK_LOCKS; i++)
2417836SJohn.Forte@Sun.COM mutex_init(&_sd_buflist.hook_locks[i], NULL, MUTEX_DRIVER,
2429093SRamana.Srikanth@Sun.COM NULL);
2437836SJohn.Forte@Sun.COM
2447836SJohn.Forte@Sun.COM cv_init(&_sd_buflist.hook_wait, NULL, CV_DRIVER, NULL);
2457836SJohn.Forte@Sun.COM _sd_buflist.hook_waiters = 0;
2467836SJohn.Forte@Sun.COM
2477836SJohn.Forte@Sun.COM sdbc_bio_count = 0;
2487836SJohn.Forte@Sun.COM SD_WRITES_TOT = 0;
2497836SJohn.Forte@Sun.COM bzero(SD_WRITES_LEN, sizeof (SD_WRITES_LEN));
2507836SJohn.Forte@Sun.COM
2517836SJohn.Forte@Sun.COM /* pagelist i/o pages must be done in cache_init */
2527836SJohn.Forte@Sun.COM
2537836SJohn.Forte@Sun.COM page_size = ptob(1);
2547836SJohn.Forte@Sun.COM page_offset_mask = page_size - 1;
2557836SJohn.Forte@Sun.COM
2567836SJohn.Forte@Sun.COM return (0);
2577836SJohn.Forte@Sun.COM }
2587836SJohn.Forte@Sun.COM
2597836SJohn.Forte@Sun.COM /*
2607836SJohn.Forte@Sun.COM * _sdbc_iobuf_deconfigure - release all memory allocated for buf list
2617836SJohn.Forte@Sun.COM *
2627836SJohn.Forte@Sun.COM * ARGUMENTS:
2637836SJohn.Forte@Sun.COM * None.
2647836SJohn.Forte@Sun.COM *
2657836SJohn.Forte@Sun.COM * RETURNS:
2667836SJohn.Forte@Sun.COM * 0
2677836SJohn.Forte@Sun.COM */
2687836SJohn.Forte@Sun.COM void
_sdbc_iobuf_deconfigure(void)2697836SJohn.Forte@Sun.COM _sdbc_iobuf_deconfigure(void)
2707836SJohn.Forte@Sun.COM {
2717836SJohn.Forte@Sun.COM ushort_t i;
2727836SJohn.Forte@Sun.COM
2737836SJohn.Forte@Sun.COM if (_sd_buflist.hooks) {
2747836SJohn.Forte@Sun.COM for (i = 0; i < _sd_buflist.bl_init_count; i ++) {
2757836SJohn.Forte@Sun.COM cv_destroy(&_sd_buflist.hooks[i].wait);
2767836SJohn.Forte@Sun.COM }
2777836SJohn.Forte@Sun.COM cv_destroy(&_sd_buflist.hook_wait);
2787836SJohn.Forte@Sun.COM nsc_kmem_free(_sd_buflist.hooks,
2799093SRamana.Srikanth@Sun.COM _sd_buflist.bl_init_count * sizeof (iob_hook_t));
2807836SJohn.Forte@Sun.COM for (i = 0; i < MAX_HOOK_LOCKS; i ++) {
2817836SJohn.Forte@Sun.COM mutex_destroy(&_sd_buflist.hook_locks[i]);
2827836SJohn.Forte@Sun.COM }
2837836SJohn.Forte@Sun.COM }
2847836SJohn.Forte@Sun.COM
2857836SJohn.Forte@Sun.COM _sd_buflist.hooks = NULL;
2867836SJohn.Forte@Sun.COM
2877836SJohn.Forte@Sun.COM #ifdef DEBUG
2887836SJohn.Forte@Sun.COM {
2897836SJohn.Forte@Sun.COM void _sdbc_ioj_clear_err(int);
2907836SJohn.Forte@Sun.COM _sdbc_ioj_clear_err(-1); /* clear any injected i/o errors */
2917836SJohn.Forte@Sun.COM _sdbc_ioj_set_dev(-1, 0); /* clear dev entries */
2927836SJohn.Forte@Sun.COM }
2937836SJohn.Forte@Sun.COM #endif
2947836SJohn.Forte@Sun.COM
2957836SJohn.Forte@Sun.COM }
2967836SJohn.Forte@Sun.COM
2977836SJohn.Forte@Sun.COM /*
2987836SJohn.Forte@Sun.COM * _sd_pending_iobuf()
2997836SJohn.Forte@Sun.COM *
3007836SJohn.Forte@Sun.COM * Return the number of I/O bufs outstanding
3017836SJohn.Forte@Sun.COM */
3027836SJohn.Forte@Sun.COM int
_sd_pending_iobuf(void)3037836SJohn.Forte@Sun.COM _sd_pending_iobuf(void)
3047836SJohn.Forte@Sun.COM {
3057836SJohn.Forte@Sun.COM return (sdbc_bio_count);
3067836SJohn.Forte@Sun.COM }
3077836SJohn.Forte@Sun.COM
3087836SJohn.Forte@Sun.COM /*
3097836SJohn.Forte@Sun.COM * _sd_get_iobuf - allocate a buf.
3107836SJohn.Forte@Sun.COM *
3117836SJohn.Forte@Sun.COM * ARGUMENTS:
3127836SJohn.Forte@Sun.COM * None.
3137836SJohn.Forte@Sun.COM *
3147836SJohn.Forte@Sun.COM * RETURNS:
3157836SJohn.Forte@Sun.COM * NULL - failure.
3167836SJohn.Forte@Sun.COM * buf ptr otherwise.
3177836SJohn.Forte@Sun.COM *
3187836SJohn.Forte@Sun.COM * ASSUMPTIONS - process could block if we run out.
3197836SJohn.Forte@Sun.COM *
3207836SJohn.Forte@Sun.COM */
3217836SJohn.Forte@Sun.COM /*ARGSUSED*/
3227836SJohn.Forte@Sun.COM static struct buf *
_sd_get_iobuf(int num_bdl)3237836SJohn.Forte@Sun.COM _sd_get_iobuf(int num_bdl)
3247836SJohn.Forte@Sun.COM {
3257836SJohn.Forte@Sun.COM struct buf *bp;
3267836SJohn.Forte@Sun.COM
3277836SJohn.Forte@Sun.COM /* Get a buffer, ready for page list i/o */
3287836SJohn.Forte@Sun.COM
3297836SJohn.Forte@Sun.COM if (DO_PAGE_LIST)
3307836SJohn.Forte@Sun.COM bp = pageio_setup(NULL, 0, &kvp, 0);
3317836SJohn.Forte@Sun.COM else
3327836SJohn.Forte@Sun.COM bp = getrbuf(KM_SLEEP);
3337836SJohn.Forte@Sun.COM
3347836SJohn.Forte@Sun.COM if (bp == NULL)
3357836SJohn.Forte@Sun.COM return (NULL);
3367836SJohn.Forte@Sun.COM mutex_enter(&sdbc_bio_mutex);
3377836SJohn.Forte@Sun.COM sdbc_bio_count++;
3387836SJohn.Forte@Sun.COM mutex_exit(&sdbc_bio_mutex);
3397836SJohn.Forte@Sun.COM return (bp);
3407836SJohn.Forte@Sun.COM }
3417836SJohn.Forte@Sun.COM
3427836SJohn.Forte@Sun.COM /*
3437836SJohn.Forte@Sun.COM * _sd_put_iobuf - put a buf back in the freelist.
3447836SJohn.Forte@Sun.COM *
3457836SJohn.Forte@Sun.COM * ARGUMENTS:
3467836SJohn.Forte@Sun.COM * bp - buf pointer.
3477836SJohn.Forte@Sun.COM *
3487836SJohn.Forte@Sun.COM * RETURNS:
3497836SJohn.Forte@Sun.COM * 0
3507836SJohn.Forte@Sun.COM *
3517836SJohn.Forte@Sun.COM */
3527836SJohn.Forte@Sun.COM static void
_sd_put_iobuf(struct buf * bp)3537836SJohn.Forte@Sun.COM _sd_put_iobuf(struct buf *bp)
3547836SJohn.Forte@Sun.COM {
3557836SJohn.Forte@Sun.COM mutex_enter(&sdbc_bio_mutex);
3567836SJohn.Forte@Sun.COM sdbc_bio_count--;
3577836SJohn.Forte@Sun.COM mutex_exit(&sdbc_bio_mutex);
3587836SJohn.Forte@Sun.COM if (DO_PAGE_LIST)
3597836SJohn.Forte@Sun.COM pageio_done(bp);
3607836SJohn.Forte@Sun.COM else
3617836SJohn.Forte@Sun.COM freerbuf(bp);
3627836SJohn.Forte@Sun.COM }
3637836SJohn.Forte@Sun.COM
3647836SJohn.Forte@Sun.COM
3657836SJohn.Forte@Sun.COM /* use for ORing only */
3667836SJohn.Forte@Sun.COM #define B_KERNBUF 0
3677836SJohn.Forte@Sun.COM
3687836SJohn.Forte@Sun.COM static void
_sd_setup_iob(struct buf * bp,dev_t dev,nsc_off_t pos,int flag)3697836SJohn.Forte@Sun.COM _sd_setup_iob(struct buf *bp, dev_t dev, nsc_off_t pos, int flag)
3707836SJohn.Forte@Sun.COM {
3717836SJohn.Forte@Sun.COM bp->b_pages = NULL;
3727836SJohn.Forte@Sun.COM bp->b_un.b_addr = 0;
3737836SJohn.Forte@Sun.COM
3747836SJohn.Forte@Sun.COM flag &= (B_READ | B_WRITE);
3757836SJohn.Forte@Sun.COM
3767836SJohn.Forte@Sun.COM /*
3777836SJohn.Forte@Sun.COM * if pagelist i/o, _sd_get_iobuf()/pageio_setup() has already
3787836SJohn.Forte@Sun.COM * set b_flags to
3797836SJohn.Forte@Sun.COM * B_KERNBUF | B_PAGEIO | B_NOCACHE | B_BUSY (sol 6,7,8)
3807836SJohn.Forte@Sun.COM * or
3817836SJohn.Forte@Sun.COM * B_PAGEIO | B_NOCACHE | B_BUSY (sol 9)
3827836SJohn.Forte@Sun.COM */
3837836SJohn.Forte@Sun.COM
3847836SJohn.Forte@Sun.COM bp->b_flags |= B_KERNBUF | B_BUSY | flag;
3857836SJohn.Forte@Sun.COM
3867836SJohn.Forte@Sun.COM bp->b_error = 0;
3877836SJohn.Forte@Sun.COM
3887836SJohn.Forte@Sun.COM bp->b_forw = NULL;
3897836SJohn.Forte@Sun.COM bp->b_back = NULL;
3907836SJohn.Forte@Sun.COM
3917836SJohn.Forte@Sun.COM bp->b_lblkno = (diskaddr_t)pos;
3927836SJohn.Forte@Sun.COM bp->b_bufsize = 0;
3937836SJohn.Forte@Sun.COM bp->b_resid = 0;
3947836SJohn.Forte@Sun.COM bp->b_proc = NULL;
3957836SJohn.Forte@Sun.COM bp->b_edev = dev;
3967836SJohn.Forte@Sun.COM }
3977836SJohn.Forte@Sun.COM
3987836SJohn.Forte@Sun.COM
3997836SJohn.Forte@Sun.COM /*
4007836SJohn.Forte@Sun.COM * _sd_get_hook - get an iob hook from the free list.
4017836SJohn.Forte@Sun.COM *
4027836SJohn.Forte@Sun.COM * ARGUMENTS:
4037836SJohn.Forte@Sun.COM * none
4047836SJohn.Forte@Sun.COM *
4057836SJohn.Forte@Sun.COM * RETURNS:
4067836SJohn.Forte@Sun.COM * the newly allocated iob_hook.
4077836SJohn.Forte@Sun.COM *
4087836SJohn.Forte@Sun.COM */
4097836SJohn.Forte@Sun.COM static iob_hook_t *
_sd_get_hook(void)4107836SJohn.Forte@Sun.COM _sd_get_hook(void)
4117836SJohn.Forte@Sun.COM {
4127836SJohn.Forte@Sun.COM
4137836SJohn.Forte@Sun.COM iob_hook_t *ret;
4147836SJohn.Forte@Sun.COM
4157836SJohn.Forte@Sun.COM mutex_enter(&sdbc_bio_mutex);
4167836SJohn.Forte@Sun.COM
4177836SJohn.Forte@Sun.COM retry:
4187836SJohn.Forte@Sun.COM ret = _sd_buflist.hook_head;
4197836SJohn.Forte@Sun.COM if (ret)
4207836SJohn.Forte@Sun.COM _sd_buflist.hook_head = ret->next_hook;
4217836SJohn.Forte@Sun.COM else {
4227836SJohn.Forte@Sun.COM ++_sd_buflist.hook_waiters;
4237836SJohn.Forte@Sun.COM if (_sd_buflist.max_hook_waiters < _sd_buflist.hook_waiters)
4247836SJohn.Forte@Sun.COM _sd_buflist.max_hook_waiters = _sd_buflist.hook_waiters;
4257836SJohn.Forte@Sun.COM cv_wait(&_sd_buflist.hook_wait, &sdbc_bio_mutex);
4267836SJohn.Forte@Sun.COM --_sd_buflist.hook_waiters;
4277836SJohn.Forte@Sun.COM goto retry;
4287836SJohn.Forte@Sun.COM }
4297836SJohn.Forte@Sun.COM
4307836SJohn.Forte@Sun.COM if (_sd_buflist.bl_hook_lowmark > --_sd_buflist.bl_hooks_avail)
4317836SJohn.Forte@Sun.COM _sd_buflist.bl_hook_lowmark = _sd_buflist.bl_hooks_avail;
4327836SJohn.Forte@Sun.COM
4337836SJohn.Forte@Sun.COM mutex_exit(&sdbc_bio_mutex);
4347836SJohn.Forte@Sun.COM ret->skipped = 0;
4357836SJohn.Forte@Sun.COM
4367836SJohn.Forte@Sun.COM ret->count = 0;
4377836SJohn.Forte@Sun.COM
4387836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
4397836SJohn.Forte@Sun.COM ret->PAGE_IO = 0;
4407836SJohn.Forte@Sun.COM ret->NORM_IO = 0;
4417836SJohn.Forte@Sun.COM ret->NORM_IO_SIZE = 0;
4427836SJohn.Forte@Sun.COM ret->SKIP_IO = 0;
4437836SJohn.Forte@Sun.COM ret->PAGE_COMBINED = 0;
4447836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
4457836SJohn.Forte@Sun.COM
4467836SJohn.Forte@Sun.COM return (ret);
4477836SJohn.Forte@Sun.COM }
4487836SJohn.Forte@Sun.COM
4497836SJohn.Forte@Sun.COM /*
4507836SJohn.Forte@Sun.COM * _sd_put_hook - put an iob hook back on the free list.
4517836SJohn.Forte@Sun.COM *
4527836SJohn.Forte@Sun.COM * ARGUMENTS:
4537836SJohn.Forte@Sun.COM * hook - an iob_hook to be returned to the freelist.
4547836SJohn.Forte@Sun.COM *
4557836SJohn.Forte@Sun.COM *
4567836SJohn.Forte@Sun.COM */
4577836SJohn.Forte@Sun.COM static void
_sd_put_hook(iob_hook_t * hook)4587836SJohn.Forte@Sun.COM _sd_put_hook(iob_hook_t *hook)
4597836SJohn.Forte@Sun.COM {
4607836SJohn.Forte@Sun.COM
4617836SJohn.Forte@Sun.COM mutex_enter(&sdbc_bio_mutex);
4627836SJohn.Forte@Sun.COM
4637836SJohn.Forte@Sun.COM if (_sd_buflist.hook_waiters) {
4647836SJohn.Forte@Sun.COM cv_signal(&_sd_buflist.hook_wait);
4657836SJohn.Forte@Sun.COM }
4667836SJohn.Forte@Sun.COM hook->next_hook = _sd_buflist.hook_head;
4677836SJohn.Forte@Sun.COM _sd_buflist.hook_head = hook;
4687836SJohn.Forte@Sun.COM
4697836SJohn.Forte@Sun.COM ++_sd_buflist.bl_hooks_avail;
4707836SJohn.Forte@Sun.COM
4717836SJohn.Forte@Sun.COM mutex_exit(&sdbc_bio_mutex);
4727836SJohn.Forte@Sun.COM }
4737836SJohn.Forte@Sun.COM
4747836SJohn.Forte@Sun.COM /*
4757836SJohn.Forte@Sun.COM * _sd_extend_iob - the i/o block we are handling needs a new struct buf to
4767836SJohn.Forte@Sun.COM * describe the next hunk of i/o. Get a new struct buf initialize it based
4777836SJohn.Forte@Sun.COM * on the state in the struct buf we are passed as an arg.
4787836SJohn.Forte@Sun.COM * ARGUMENTS:
4797836SJohn.Forte@Sun.COM * head_bp - a buffer header in the current i/o block we are handling.
4807836SJohn.Forte@Sun.COM * (generally the initial header but in fact could be any
4817836SJohn.Forte@Sun.COM * of the ones [if any] that were chained to the initial
4827836SJohn.Forte@Sun.COM * one).
4837836SJohn.Forte@Sun.COM */
4847836SJohn.Forte@Sun.COM static struct buf *
_sd_extend_iob(struct buf * head_bp)4857836SJohn.Forte@Sun.COM _sd_extend_iob(struct buf *head_bp)
4867836SJohn.Forte@Sun.COM {
4877836SJohn.Forte@Sun.COM struct buf *bp;
4887836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)head_bp->b_private;
4897836SJohn.Forte@Sun.COM
4907836SJohn.Forte@Sun.COM
4917836SJohn.Forte@Sun.COM if (!(bp = _sd_get_iobuf(0)))
4927836SJohn.Forte@Sun.COM return (0);
4937836SJohn.Forte@Sun.COM
4947836SJohn.Forte@Sun.COM bp->b_pages = NULL;
4957836SJohn.Forte@Sun.COM bp->b_un.b_addr = 0;
4967836SJohn.Forte@Sun.COM
4977836SJohn.Forte@Sun.COM bp->b_flags |= (head_bp->b_flags & (B_READ | B_WRITE));
4987836SJohn.Forte@Sun.COM
4997836SJohn.Forte@Sun.COM if (!DO_PAGE_LIST)
5007836SJohn.Forte@Sun.COM bp->b_flags |= B_KERNBUF | B_BUSY;
5017836SJohn.Forte@Sun.COM
5027836SJohn.Forte@Sun.COM bp->b_error = 0;
5037836SJohn.Forte@Sun.COM
5047836SJohn.Forte@Sun.COM /*
5057836SJohn.Forte@Sun.COM * b_forw/b_back will form a doubly linked list of all the buffers
5067836SJohn.Forte@Sun.COM * associated with this block of i/o.
5077836SJohn.Forte@Sun.COM * hook->tail points to the last buffer in the chain.
5087836SJohn.Forte@Sun.COM */
5097836SJohn.Forte@Sun.COM bp->b_forw = NULL;
5107836SJohn.Forte@Sun.COM bp->b_back = hook->tail;
5117836SJohn.Forte@Sun.COM hook->tail->b_forw = bp;
5127836SJohn.Forte@Sun.COM hook->tail = bp;
5137836SJohn.Forte@Sun.COM hook->count++;
5147836SJohn.Forte@Sun.COM
5157836SJohn.Forte@Sun.COM ASSERT(BLK_FBA_OFF(hook->size) == 0);
5167836SJohn.Forte@Sun.COM
5177836SJohn.Forte@Sun.COM bp->b_lblkno = (diskaddr_t)hook->start_fba +
5189093SRamana.Srikanth@Sun.COM (diskaddr_t)FBA_NUM(hook->size);
5197836SJohn.Forte@Sun.COM
5207836SJohn.Forte@Sun.COM bp->b_bufsize = 0;
5217836SJohn.Forte@Sun.COM bp->b_resid = 0;
5227836SJohn.Forte@Sun.COM bp->b_proc = NULL;
5237836SJohn.Forte@Sun.COM bp->b_edev = head_bp->b_edev;
5247836SJohn.Forte@Sun.COM
5257836SJohn.Forte@Sun.COM bp->b_iodone = NULL; /* for now */
5267836SJohn.Forte@Sun.COM bp->b_private = hook;
5277836SJohn.Forte@Sun.COM
5287836SJohn.Forte@Sun.COM return (bp);
5297836SJohn.Forte@Sun.COM }
5307836SJohn.Forte@Sun.COM
5317836SJohn.Forte@Sun.COM /*
5327836SJohn.Forte@Sun.COM * sd_alloc_iob - start processing a block of i/o. This allocates an initial
5337836SJohn.Forte@Sun.COM * buffer header for describing the i/o and a iob_hook for collecting
5347836SJohn.Forte@Sun.COM * information about all the i/o requests added to this buffer.
5357836SJohn.Forte@Sun.COM *
5367836SJohn.Forte@Sun.COM * ARGUMENTS:
5377836SJohn.Forte@Sun.COM * dev - the device all the i/o is destined for.
5387836SJohn.Forte@Sun.COM * fba_pos - the initial disk block to read.
5397836SJohn.Forte@Sun.COM * blks - ignored
5407836SJohn.Forte@Sun.COM * flag - signal whether this is a read or write request.
5417836SJohn.Forte@Sun.COM *
5427836SJohn.Forte@Sun.COM * RETURNS:
5437836SJohn.Forte@Sun.COM * pointer to free struct buf which will be used to describe i/o request.
5447836SJohn.Forte@Sun.COM */
5457836SJohn.Forte@Sun.COM /* ARGSUSED */
5467836SJohn.Forte@Sun.COM struct buf *
sd_alloc_iob(dev_t dev,nsc_off_t fba_pos,int blks,int flag)5477836SJohn.Forte@Sun.COM sd_alloc_iob(dev_t dev, nsc_off_t fba_pos, int blks, int flag)
5487836SJohn.Forte@Sun.COM {
5497836SJohn.Forte@Sun.COM struct buf *bp;
5507836SJohn.Forte@Sun.COM iob_hook_t *hook;
5517836SJohn.Forte@Sun.COM
5527836SJohn.Forte@Sun.COM if (!(bp = _sd_get_iobuf(0)))
5537836SJohn.Forte@Sun.COM return (0);
5547836SJohn.Forte@Sun.COM
5557836SJohn.Forte@Sun.COM _sd_setup_iob(bp, dev, fba_pos, flag);
5567836SJohn.Forte@Sun.COM
5577836SJohn.Forte@Sun.COM bp->b_iodone = NULL; /* for now */
5587836SJohn.Forte@Sun.COM hook = _sd_get_hook();
5597836SJohn.Forte@Sun.COM if (!hook) {
5607836SJohn.Forte@Sun.COM /* can't see how this could happen */
5617836SJohn.Forte@Sun.COM _sd_put_iobuf(bp);
5627836SJohn.Forte@Sun.COM return (0);
5637836SJohn.Forte@Sun.COM }
5647836SJohn.Forte@Sun.COM
5657836SJohn.Forte@Sun.COM /*
5667836SJohn.Forte@Sun.COM * pick an arbitrary lock
5677836SJohn.Forte@Sun.COM */
5687836SJohn.Forte@Sun.COM hook->lockp = &_sd_buflist.hook_locks[((long)hook >> 9) &
5699093SRamana.Srikanth@Sun.COM (MAX_HOOK_LOCKS - 1)];
5707836SJohn.Forte@Sun.COM hook->start_fba = fba_pos;
5717836SJohn.Forte@Sun.COM hook->last_fba = fba_pos;
5727836SJohn.Forte@Sun.COM hook->size = 0;
5737836SJohn.Forte@Sun.COM hook->tail = bp;
5747836SJohn.Forte@Sun.COM hook->chain = bp;
5757836SJohn.Forte@Sun.COM hook->count = 1;
5767836SJohn.Forte@Sun.COM hook->error = 0;
5777836SJohn.Forte@Sun.COM bp->b_private = hook;
5787836SJohn.Forte@Sun.COM
5797836SJohn.Forte@Sun.COM return (bp);
5807836SJohn.Forte@Sun.COM }
5817836SJohn.Forte@Sun.COM
5827836SJohn.Forte@Sun.COM /*
5837836SJohn.Forte@Sun.COM * _sd_pack_pages - produce i/o requests that will perform the type of i/o
5847836SJohn.Forte@Sun.COM * described by bp (READ/WRITE). It attempt to tack the i/o onto the
5857836SJohn.Forte@Sun.COM * buf pointer to by list to minimize the number of bufs required.
5867836SJohn.Forte@Sun.COM *
5877836SJohn.Forte@Sun.COM * ARGUMENTS:
5887836SJohn.Forte@Sun.COM * bp - is the i/o description i.e. head
5897836SJohn.Forte@Sun.COM * list - is where to start adding this i/o request (null if we should extend)
5907836SJohn.Forte@Sun.COM * addr - address describing where the data is.
5917836SJohn.Forte@Sun.COM * offset - offset from addr where data begins
5927836SJohn.Forte@Sun.COM * size - size of the i/o request.
5937836SJohn.Forte@Sun.COM */
5947836SJohn.Forte@Sun.COM static void
_sd_pack_pages(struct buf * bp,struct buf * list,sd_addr_t * addr,nsc_off_t offset,nsc_size_t size)5957836SJohn.Forte@Sun.COM _sd_pack_pages(struct buf *bp, struct buf *list, sd_addr_t *addr,
5967836SJohn.Forte@Sun.COM nsc_off_t offset, nsc_size_t size)
5977836SJohn.Forte@Sun.COM {
5987836SJohn.Forte@Sun.COM uintptr_t start_addr, end_addr;
5997836SJohn.Forte@Sun.COM int page_end_aligned;
6007836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
6017836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)bp->b_private;
6027836SJohn.Forte@Sun.COM struct buf *orig_list = list;
6037836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
6047836SJohn.Forte@Sun.COM
6057836SJohn.Forte@Sun.COM start_addr = (uintptr_t)addr->sa_virt + offset;
6067836SJohn.Forte@Sun.COM end_addr = start_addr + size;
6077836SJohn.Forte@Sun.COM
6087836SJohn.Forte@Sun.COM page_end_aligned = !(end_addr & page_offset_mask);
6097836SJohn.Forte@Sun.COM
6107836SJohn.Forte@Sun.COM if (!list && !(list = _sd_extend_iob(bp))) {
6117836SJohn.Forte@Sun.COM /*
6127836SJohn.Forte@Sun.COM * we're hosed since we have no error return...
6137836SJohn.Forte@Sun.COM * though we could ignore stuff from here on out
6147836SJohn.Forte@Sun.COM * and return ENOMEM when we get to sd_start_io.
6157836SJohn.Forte@Sun.COM * This will do for now.
6167836SJohn.Forte@Sun.COM */
6177836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "_sd_pack_pages: couldn't extend iob");
6187836SJohn.Forte@Sun.COM }
6197836SJohn.Forte@Sun.COM
6207836SJohn.Forte@Sun.COM /*
6217836SJohn.Forte@Sun.COM * We only want to do pagelist i/o if we end on a page boundary.
6227836SJohn.Forte@Sun.COM * If we don't end on a page boundary we won't combine with the
6237836SJohn.Forte@Sun.COM * next request and so we may as well do it as normal as it
6247836SJohn.Forte@Sun.COM * will only use one buffer.
6257836SJohn.Forte@Sun.COM */
6267836SJohn.Forte@Sun.COM
6277836SJohn.Forte@Sun.COM if (DO_PAGE_LIST && page_end_aligned) {
6287836SJohn.Forte@Sun.COM if (start_addr & page_offset_mask) {
6297836SJohn.Forte@Sun.COM /*
6307836SJohn.Forte@Sun.COM * handle the partial page
6317836SJohn.Forte@Sun.COM */
6327836SJohn.Forte@Sun.COM if (list->b_bufsize) {
6337836SJohn.Forte@Sun.COM if (!(list = _sd_extend_iob(bp))) {
6347836SJohn.Forte@Sun.COM /*
6357836SJohn.Forte@Sun.COM * we're hosed since we have no error
6367836SJohn.Forte@Sun.COM * return though we could ignore stuff
6377836SJohn.Forte@Sun.COM * from here on out and return ENOMEM
6387836SJohn.Forte@Sun.COM * when we get to sd_start_io.
6397836SJohn.Forte@Sun.COM * This will do for now.
6407836SJohn.Forte@Sun.COM */
6417836SJohn.Forte@Sun.COM cmn_err(CE_PANIC,
6427836SJohn.Forte@Sun.COM "_sd_pack_pages: couldn't extend iob");
6437836SJohn.Forte@Sun.COM }
6447836SJohn.Forte@Sun.COM }
6457836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
6467836SJohn.Forte@Sun.COM hook->PAGE_IO++;
6477836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
6487836SJohn.Forte@Sun.COM _sd_add_vm_to_bp_plist(list,
6499093SRamana.Srikanth@Sun.COM (unsigned char *) start_addr);
6507836SJohn.Forte@Sun.COM list->b_bufsize = page_size -
6519093SRamana.Srikanth@Sun.COM (start_addr & page_offset_mask);
6527836SJohn.Forte@Sun.COM list->b_un.b_addr = (caddr_t)
6539093SRamana.Srikanth@Sun.COM (start_addr & page_offset_mask);
6547836SJohn.Forte@Sun.COM size -= list->b_bufsize;
6557836SJohn.Forte@Sun.COM start_addr += list->b_bufsize;
6567836SJohn.Forte@Sun.COM }
6577836SJohn.Forte@Sun.COM /*
6587836SJohn.Forte@Sun.COM * Now fill with all the full pages remaining.
6597836SJohn.Forte@Sun.COM */
6607836SJohn.Forte@Sun.COM for (; size > 0; size -= page_size) {
6617836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
6627836SJohn.Forte@Sun.COM hook->PAGE_IO++;
6637836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
6647836SJohn.Forte@Sun.COM
6657836SJohn.Forte@Sun.COM _sd_add_vm_to_bp_plist(list,
6669093SRamana.Srikanth@Sun.COM (unsigned char *) start_addr);
6677836SJohn.Forte@Sun.COM start_addr += page_size;
6687836SJohn.Forte@Sun.COM list->b_bufsize += page_size;
6697836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
6707836SJohn.Forte@Sun.COM if (list == orig_list)
6717836SJohn.Forte@Sun.COM hook->PAGE_COMBINED++;
6727836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
6737836SJohn.Forte@Sun.COM }
6747836SJohn.Forte@Sun.COM if (size)
6757836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "_sd_pack_pages: bad size: %"
6767836SJohn.Forte@Sun.COM NSC_SZFMT, size);
6777836SJohn.Forte@Sun.COM } else {
6787836SJohn.Forte@Sun.COM /*
6797836SJohn.Forte@Sun.COM * Wasn't worth it as pagelist i/o, do as normal
6807836SJohn.Forte@Sun.COM */
6817836SJohn.Forte@Sun.COM if (list->b_bufsize && !(list = _sd_extend_iob(bp))) {
6827836SJohn.Forte@Sun.COM /*
6837836SJohn.Forte@Sun.COM * we're hosed since we have no error return...
6847836SJohn.Forte@Sun.COM * though we could ignore stuff from here on out
6857836SJohn.Forte@Sun.COM * and return ENOMEM when we get to sd_start_io.
6867836SJohn.Forte@Sun.COM * This will do for now.
6877836SJohn.Forte@Sun.COM */
6887836SJohn.Forte@Sun.COM cmn_err(CE_PANIC,
6899093SRamana.Srikanth@Sun.COM "_sd_pack_pages: couldn't extend iob");
6907836SJohn.Forte@Sun.COM }
6917836SJohn.Forte@Sun.COM
6927836SJohn.Forte@Sun.COM /* kernel virtual */
6937836SJohn.Forte@Sun.COM list->b_flags &= ~(B_PHYS | B_PAGEIO);
6947836SJohn.Forte@Sun.COM list->b_un.b_addr = (caddr_t)start_addr;
6957836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
6967836SJohn.Forte@Sun.COM hook->NORM_IO++;
6977836SJohn.Forte@Sun.COM hook->NORM_IO_SIZE += size;
6987836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
6997836SJohn.Forte@Sun.COM list->b_bufsize = (size_t)size;
7007836SJohn.Forte@Sun.COM }
7017836SJohn.Forte@Sun.COM
7027836SJohn.Forte@Sun.COM }
7037836SJohn.Forte@Sun.COM
7047836SJohn.Forte@Sun.COM /*
7057836SJohn.Forte@Sun.COM * perform same function as _sd_pack_pages() when not doing pageio
7067836SJohn.Forte@Sun.COM */
7077836SJohn.Forte@Sun.COM static void
_sd_pack_pages_nopageio(struct buf * bp,struct buf * list,sd_addr_t * addr,nsc_off_t offset,nsc_size_t size)7087836SJohn.Forte@Sun.COM _sd_pack_pages_nopageio(struct buf *bp, struct buf *list, sd_addr_t *addr,
7097836SJohn.Forte@Sun.COM nsc_off_t offset, nsc_size_t size)
7107836SJohn.Forte@Sun.COM {
7117836SJohn.Forte@Sun.COM uintptr_t start_addr;
7127836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
7137836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)bp->b_private;
7147836SJohn.Forte@Sun.COM struct buf *orig_list = list;
7157836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
7167836SJohn.Forte@Sun.COM
7177836SJohn.Forte@Sun.COM start_addr = (uintptr_t)addr->sa_virt + offset;
7187836SJohn.Forte@Sun.COM
7197836SJohn.Forte@Sun.COM if (!list && !(list = _sd_extend_iob(bp))) {
7207836SJohn.Forte@Sun.COM /*
7217836SJohn.Forte@Sun.COM * we're hosed since we have no error return...
7227836SJohn.Forte@Sun.COM * though we could ignore stuff from here on out
7237836SJohn.Forte@Sun.COM * and return ENOMEM when we get to sd_start_io.
7247836SJohn.Forte@Sun.COM * This will do for now.
7257836SJohn.Forte@Sun.COM */
7267836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "_sd_pack_pages_nopageio: couldn't "
7279093SRamana.Srikanth@Sun.COM "extend iob");
7287836SJohn.Forte@Sun.COM }
7297836SJohn.Forte@Sun.COM
7307836SJohn.Forte@Sun.COM if (list->b_bufsize &&
7317836SJohn.Forte@Sun.COM (start_addr == (uintptr_t)(list->b_un.b_addr + list->b_bufsize))) {
7327836SJohn.Forte@Sun.COM /* contiguous */
7337836SJohn.Forte@Sun.COM list->b_bufsize += (size_t)size;
7347836SJohn.Forte@Sun.COM } else {
7357836SJohn.Forte@Sun.COM /*
7367836SJohn.Forte@Sun.COM * not contiguous mem (extend) or first buffer (bufsize == 0).
7377836SJohn.Forte@Sun.COM */
7387836SJohn.Forte@Sun.COM if (list->b_bufsize && !(list = _sd_extend_iob(bp))) {
7397836SJohn.Forte@Sun.COM /*
7407836SJohn.Forte@Sun.COM * we're hosed since we have no error return...
7417836SJohn.Forte@Sun.COM * though we could ignore stuff from here on out
7427836SJohn.Forte@Sun.COM * and return ENOMEM when we get to sd_start_io.
7437836SJohn.Forte@Sun.COM * This will do for now.
7447836SJohn.Forte@Sun.COM */
7457836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "_sd_pack_pages_nopageio: couldn't "
7469093SRamana.Srikanth@Sun.COM "extend iob");
7477836SJohn.Forte@Sun.COM }
7487836SJohn.Forte@Sun.COM list->b_un.b_addr = (caddr_t)start_addr;
7497836SJohn.Forte@Sun.COM list->b_bufsize = (size_t)size;
7507836SJohn.Forte@Sun.COM }
7517836SJohn.Forte@Sun.COM
7527836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
7537836SJohn.Forte@Sun.COM hook->NORM_IO++;
7547836SJohn.Forte@Sun.COM hook->NORM_IO_SIZE += size;
7557836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
7567836SJohn.Forte@Sun.COM }
7577836SJohn.Forte@Sun.COM
7587836SJohn.Forte@Sun.COM /*
7597836SJohn.Forte@Sun.COM * sd_add_fba - add an i/o request to the block of i/o described by bp.
7607836SJohn.Forte@Sun.COM * We try and combine this request with the previous request. In
7617836SJohn.Forte@Sun.COM * Addition we try and do the i/o as PAGELIST_IO if it satisfies
7627836SJohn.Forte@Sun.COM * the restrictions for it. If the i/o request can't be combined
7637836SJohn.Forte@Sun.COM * we extend the i/o description with a new buffer header and add
7647836SJohn.Forte@Sun.COM * it to the chain headed by bp.
7657836SJohn.Forte@Sun.COM *
7667836SJohn.Forte@Sun.COM * ARGUMENTS:
7677836SJohn.Forte@Sun.COM * bp - the struct buf describing the block i/o we are collecting.
7687836SJohn.Forte@Sun.COM * addr - description of the address where the data will read/written to.
7697836SJohn.Forte@Sun.COM * A NULL indicates that this i/o request doesn't need to actually
7707836SJohn.Forte@Sun.COM * happen. Used to mark reads when the fba is already in cache and
7717836SJohn.Forte@Sun.COM * dirty.
7727836SJohn.Forte@Sun.COM *
7737836SJohn.Forte@Sun.COM * fba_pos - offset from address in addr where the i/o is to start.
7747836SJohn.Forte@Sun.COM *
7757836SJohn.Forte@Sun.COM * fba_len - number of consecutive fbas to transfer.
7767836SJohn.Forte@Sun.COM *
7777836SJohn.Forte@Sun.COM * NOTE: It is assumed that the memory is physically contiguous but may span
7787836SJohn.Forte@Sun.COM * multiple pages (should a cache block be larger than a page).
7797836SJohn.Forte@Sun.COM *
7807836SJohn.Forte@Sun.COM */
7817836SJohn.Forte@Sun.COM void
sd_add_fba(struct buf * bp,sd_addr_t * addr,nsc_off_t fba_pos,nsc_size_t fba_len)7827836SJohn.Forte@Sun.COM sd_add_fba(struct buf *bp, sd_addr_t *addr, nsc_off_t fba_pos,
7837836SJohn.Forte@Sun.COM nsc_size_t fba_len)
7847836SJohn.Forte@Sun.COM {
7857836SJohn.Forte@Sun.COM nsc_off_t offset;
7867836SJohn.Forte@Sun.COM nsc_size_t size;
7877836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)bp->b_private;
7887836SJohn.Forte@Sun.COM
7897836SJohn.Forte@Sun.COM size = FBA_SIZE(fba_len);
7907836SJohn.Forte@Sun.COM offset = FBA_SIZE(fba_pos);
7917836SJohn.Forte@Sun.COM
7927836SJohn.Forte@Sun.COM if (addr) {
7937836SJohn.Forte@Sun.COM /*
7947836SJohn.Forte@Sun.COM * See if this can be combined with previous request(s)
7957836SJohn.Forte@Sun.COM */
7967836SJohn.Forte@Sun.COM if (!bp->b_bufsize) {
7977836SJohn.Forte@Sun.COM if (DO_PAGE_LIST)
7987836SJohn.Forte@Sun.COM _sd_pack_pages(bp, bp, addr, offset, size);
7997836SJohn.Forte@Sun.COM else
8007836SJohn.Forte@Sun.COM _sd_pack_pages_nopageio(bp, bp, addr, offset,
8019093SRamana.Srikanth@Sun.COM size);
8027836SJohn.Forte@Sun.COM } else {
8037836SJohn.Forte@Sun.COM if (DO_PAGE_LIST) {
8047836SJohn.Forte@Sun.COM if (hook->tail->b_flags & B_PAGEIO) {
8057836SJohn.Forte@Sun.COM /*
8067836SJohn.Forte@Sun.COM * Last buffer was a pagelist. Unless a
8077836SJohn.Forte@Sun.COM * skip was detected the last request
8087836SJohn.Forte@Sun.COM * ended on a page boundary. If this
8097836SJohn.Forte@Sun.COM * one starts on one we combine the
8107836SJohn.Forte@Sun.COM * best we can.
8117836SJohn.Forte@Sun.COM */
8127836SJohn.Forte@Sun.COM if (hook->skipped)
8137836SJohn.Forte@Sun.COM _sd_pack_pages(bp, NULL, addr,
8149093SRamana.Srikanth@Sun.COM offset, size);
8157836SJohn.Forte@Sun.COM else
8167836SJohn.Forte@Sun.COM _sd_pack_pages(bp, hook->tail,
8179093SRamana.Srikanth@Sun.COM addr, offset, size);
8187836SJohn.Forte@Sun.COM } else {
8197836SJohn.Forte@Sun.COM /*
8207836SJohn.Forte@Sun.COM * Last buffer was vanilla i/o or worse
8217836SJohn.Forte@Sun.COM * (sd_add_mem)
8227836SJohn.Forte@Sun.COM */
8237836SJohn.Forte@Sun.COM _sd_pack_pages(bp, NULL, addr, offset,
8249093SRamana.Srikanth@Sun.COM size);
8257836SJohn.Forte@Sun.COM }
8267836SJohn.Forte@Sun.COM } else {
8277836SJohn.Forte@Sun.COM if (hook->skipped)
8287836SJohn.Forte@Sun.COM _sd_pack_pages_nopageio(bp, NULL,
8299093SRamana.Srikanth@Sun.COM addr, offset, size);
8307836SJohn.Forte@Sun.COM else
8317836SJohn.Forte@Sun.COM _sd_pack_pages_nopageio(bp,
8329093SRamana.Srikanth@Sun.COM hook->tail, addr, offset, size);
8337836SJohn.Forte@Sun.COM }
8347836SJohn.Forte@Sun.COM }
8357836SJohn.Forte@Sun.COM hook->skipped = 0;
8367836SJohn.Forte@Sun.COM } else {
8377836SJohn.Forte@Sun.COM /* Must be a read of dirty block we want to discard */
8387836SJohn.Forte@Sun.COM
8397836SJohn.Forte@Sun.COM ASSERT(bp->b_flags & B_READ);
8407836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
8417836SJohn.Forte@Sun.COM hook->SKIP_IO++;
8427836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
8437836SJohn.Forte@Sun.COM hook->skipped = 1;
8447836SJohn.Forte@Sun.COM if (!bp->b_bufsize)
8457836SJohn.Forte@Sun.COM bp->b_lblkno += fba_len;
8467836SJohn.Forte@Sun.COM }
8477836SJohn.Forte@Sun.COM hook->size += size;
8487836SJohn.Forte@Sun.COM
8497836SJohn.Forte@Sun.COM }
8507836SJohn.Forte@Sun.COM
8517836SJohn.Forte@Sun.COM /*
8527836SJohn.Forte@Sun.COM * sd_add_mem - add an i/o request to the block of i/o described by bp.
8537836SJohn.Forte@Sun.COM * The memory target for this i/o may span multiple pages and may
8547836SJohn.Forte@Sun.COM * not be physically contiguous.
8557836SJohn.Forte@Sun.COM * also the len might also not be a multiple of an fba.
8567836SJohn.Forte@Sun.COM *
8577836SJohn.Forte@Sun.COM * ARGUMENTS:
8587836SJohn.Forte@Sun.COM * bp - the struct buf describing the block i/o we are collecting.
8597836SJohn.Forte@Sun.COM *
8607836SJohn.Forte@Sun.COM * buf - target of this i/o request.
8617836SJohn.Forte@Sun.COM *
8627836SJohn.Forte@Sun.COM * len - number of bytes to transfer.
8637836SJohn.Forte@Sun.COM *
8647836SJohn.Forte@Sun.COM */
8657836SJohn.Forte@Sun.COM void
sd_add_mem(struct buf * bp,char * buf,nsc_size_t len)8667836SJohn.Forte@Sun.COM sd_add_mem(struct buf *bp, char *buf, nsc_size_t len)
8677836SJohn.Forte@Sun.COM {
8687836SJohn.Forte@Sun.COM nsc_size_t n;
8697836SJohn.Forte@Sun.COM uintptr_t start;
8707836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)bp->b_private;
8717836SJohn.Forte@Sun.COM
8727836SJohn.Forte@Sun.COM start = (uintptr_t)buf & page_offset_mask;
8737836SJohn.Forte@Sun.COM
8747836SJohn.Forte@Sun.COM for (; len > 0; buf += n, len -= n, start = 0) {
8757836SJohn.Forte@Sun.COM n = min((nsc_size_t)len, (nsc_size_t)(page_size - start));
8767836SJohn.Forte@Sun.COM /*
8777836SJohn.Forte@Sun.COM * i/o size must be multiple of an FBA since we can't
8787836SJohn.Forte@Sun.COM * count on lower level drivers to understand b_offset
8797836SJohn.Forte@Sun.COM */
8807836SJohn.Forte@Sun.COM if (BLK_FBA_OFF(n) != 0) {
8817836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
8829093SRamana.Srikanth@Sun.COM "!sdbc(sd_add_mem) i/o request not FBA sized (%"
8837836SJohn.Forte@Sun.COM NSC_SZFMT ")", n);
8847836SJohn.Forte@Sun.COM }
8857836SJohn.Forte@Sun.COM
8867836SJohn.Forte@Sun.COM if (!bp->b_bufsize) {
8877836SJohn.Forte@Sun.COM /* first request */
8887836SJohn.Forte@Sun.COM bp->b_flags &= ~(B_PHYS | B_PAGEIO);
8897836SJohn.Forte@Sun.COM bp->b_un.b_addr = buf;
8907836SJohn.Forte@Sun.COM bp->b_bufsize = (size_t)n;
8917836SJohn.Forte@Sun.COM } else {
8927836SJohn.Forte@Sun.COM struct buf *new_bp;
8937836SJohn.Forte@Sun.COM if (!(new_bp = _sd_extend_iob(bp))) {
8947836SJohn.Forte@Sun.COM /* we're hosed */
8957836SJohn.Forte@Sun.COM cmn_err(CE_PANIC,
8967836SJohn.Forte@Sun.COM "sd_add_mem: couldn't extend iob");
8977836SJohn.Forte@Sun.COM }
8987836SJohn.Forte@Sun.COM new_bp->b_flags &= ~(B_PHYS | B_PAGEIO);
8997836SJohn.Forte@Sun.COM new_bp->b_un.b_addr = buf;
9007836SJohn.Forte@Sun.COM new_bp->b_bufsize = (size_t)n;
9017836SJohn.Forte@Sun.COM }
9027836SJohn.Forte@Sun.COM hook->size += n;
9037836SJohn.Forte@Sun.COM }
9047836SJohn.Forte@Sun.COM }
9057836SJohn.Forte@Sun.COM
9067836SJohn.Forte@Sun.COM
9077836SJohn.Forte@Sun.COM /*
9087836SJohn.Forte@Sun.COM * sd_start_io - start all the i/o needed to satisfy the i/o request described
9097836SJohn.Forte@Sun.COM * by bp. If supplied the a non-NULL fn then this is an async request
9107836SJohn.Forte@Sun.COM * and we will return NSC_PENDING and call fn when all the i/o complete.
9117836SJohn.Forte@Sun.COM * Otherwise this is a synchronous request and we sleep until all the
9127836SJohn.Forte@Sun.COM * i/o is complete. If any buffer in the chain gets an error we return
9137836SJohn.Forte@Sun.COM * the first error we see (once all the i/o is complete).
9147836SJohn.Forte@Sun.COM *
9157836SJohn.Forte@Sun.COM * ARGUMENTS:
9167836SJohn.Forte@Sun.COM * bp - the struct buf describing the block i/o we are collecting.
9177836SJohn.Forte@Sun.COM *
9187836SJohn.Forte@Sun.COM * strategy - strategy function to call if known by the user, or NULL.
9197836SJohn.Forte@Sun.COM *
9207836SJohn.Forte@Sun.COM * fn - user's callback function. NULL implies synchronous request.
9217836SJohn.Forte@Sun.COM *
9227836SJohn.Forte@Sun.COM * arg - an argument passed to user's callback function.
9237836SJohn.Forte@Sun.COM *
9247836SJohn.Forte@Sun.COM */
9257836SJohn.Forte@Sun.COM int
sd_start_io(struct buf * bp,strategy_fn_t strategy,sdbc_ea_fn_t fn,blind_t arg)9267836SJohn.Forte@Sun.COM sd_start_io(struct buf *bp, strategy_fn_t strategy, sdbc_ea_fn_t fn,
9277836SJohn.Forte@Sun.COM blind_t arg)
9287836SJohn.Forte@Sun.COM {
9297836SJohn.Forte@Sun.COM int err;
9307836SJohn.Forte@Sun.COM iob_hook_t *hook = (iob_hook_t *)bp->b_private;
9317836SJohn.Forte@Sun.COM struct buf *bp_next;
9327836SJohn.Forte@Sun.COM int (*ea_fn)(struct buf *, iob_hook_t *);
9337836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
9349093SRamana.Srikanth@Sun.COM static int total_pages, total_pages_combined, total_norm;
9359093SRamana.Srikanth@Sun.COM static int total_norm_combined, total_skipped;
9367836SJohn.Forte@Sun.COM static nsc_size_t total_norm_size;
9377836SJohn.Forte@Sun.COM
9387836SJohn.Forte@Sun.COM static int total_bufs;
9397836SJohn.Forte@Sun.COM static int total_xpages_w, total_ypages_w;
9407836SJohn.Forte@Sun.COM static int total_xpages_r, total_ypages_r;
9417836SJohn.Forte@Sun.COM static int max_run_r, max_run_w;
9427836SJohn.Forte@Sun.COM
9437836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
9447836SJohn.Forte@Sun.COM
9457836SJohn.Forte@Sun.COM hook->func = fn;
9467836SJohn.Forte@Sun.COM hook->param = arg;
9477836SJohn.Forte@Sun.COM if (fn != NULL)
9487836SJohn.Forte@Sun.COM ea_fn = _sd_async_ea;
9497836SJohn.Forte@Sun.COM else
9507836SJohn.Forte@Sun.COM ea_fn = _sd_sync_ea;
9517836SJohn.Forte@Sun.COM
9527836SJohn.Forte@Sun.COM hook->iob_hook_iodone = ea_fn;
9537836SJohn.Forte@Sun.COM
9547836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
9557836SJohn.Forte@Sun.COM __start_io_count++;
9567836SJohn.Forte@Sun.COM total_pages += hook->PAGE_IO;
9577836SJohn.Forte@Sun.COM total_pages_combined += hook->PAGE_COMBINED;
9587836SJohn.Forte@Sun.COM total_norm += hook->NORM_IO;
9597836SJohn.Forte@Sun.COM total_norm_size += hook->NORM_IO_SIZE;
9607836SJohn.Forte@Sun.COM total_skipped += hook->SKIP_IO;
9617836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
9627836SJohn.Forte@Sun.COM
9637836SJohn.Forte@Sun.COM for (; bp; bp = bp_next) {
9647836SJohn.Forte@Sun.COM
9659093SRamana.Srikanth@Sun.COM DTRACE_PROBE4(sd_start_io_bufs, struct buf *, bp, long, bp->b_bufsize,
9669093SRamana.Srikanth@Sun.COM int, bp->b_flags, iob_hook_t *, hook);
9677836SJohn.Forte@Sun.COM
9687836SJohn.Forte@Sun.COM bp_next = bp->b_forw;
9697836SJohn.Forte@Sun.COM if (!(bp->b_flags & B_READ)) {
9707836SJohn.Forte@Sun.COM SD_WRITES_TOT++;
9717836SJohn.Forte@Sun.COM SD_WRITES_LEN[(bp->b_bufsize/32768) %
9729093SRamana.Srikanth@Sun.COM (sizeof (SD_WRITES_LEN)/sizeof (int))]++;
9737836SJohn.Forte@Sun.COM }
9747836SJohn.Forte@Sun.COM bp->b_iodone = hook->iob_drv_iodone;
9757836SJohn.Forte@Sun.COM bp->b_bcount = bp->b_bufsize;
9767836SJohn.Forte@Sun.COM bp->b_forw = NULL;
9777836SJohn.Forte@Sun.COM bp->b_back = NULL;
9787836SJohn.Forte@Sun.COM bp->b_private = NULL;
9797836SJohn.Forte@Sun.COM
9807836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
9817836SJohn.Forte@Sun.COM total_bufs ++;
9827836SJohn.Forte@Sun.COM if (bp->b_flags & B_PAGEIO) {
9837836SJohn.Forte@Sun.COM int i;
9847836SJohn.Forte@Sun.COM i = _sd_count_pages(bp->b_pages);
9857836SJohn.Forte@Sun.COM if (bp->b_flags & B_READ) {
9867836SJohn.Forte@Sun.COM if (i > max_run_r)
9877836SJohn.Forte@Sun.COM max_run_r = i;
9887836SJohn.Forte@Sun.COM total_xpages_r += i;
9897836SJohn.Forte@Sun.COM total_ypages_r++;
9907836SJohn.Forte@Sun.COM } else {
9917836SJohn.Forte@Sun.COM if (i > max_run_w)
9927836SJohn.Forte@Sun.COM max_run_w = i;
9937836SJohn.Forte@Sun.COM total_xpages_w += i;
9947836SJohn.Forte@Sun.COM total_ypages_w++;
9957836SJohn.Forte@Sun.COM }
9967836SJohn.Forte@Sun.COM }
9977836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
9987836SJohn.Forte@Sun.COM
9997836SJohn.Forte@Sun.COM
10007836SJohn.Forte@Sun.COM /*
10017836SJohn.Forte@Sun.COM * It's possible for us to be told to read a dirty block
10027836SJohn.Forte@Sun.COM * where all the i/o can go away (e.g. read one fba, it's
10037836SJohn.Forte@Sun.COM * in cache and dirty) so we really have nothing to do but
10047836SJohn.Forte@Sun.COM * say we're done.
10057836SJohn.Forte@Sun.COM */
10067836SJohn.Forte@Sun.COM if (bp->b_bcount) {
10077836SJohn.Forte@Sun.COM if (!strategy) {
10087836SJohn.Forte@Sun.COM strategy =
10097836SJohn.Forte@Sun.COM nsc_get_strategy(getmajor(bp->b_edev));
10107836SJohn.Forte@Sun.COM }
10117836SJohn.Forte@Sun.COM
10127836SJohn.Forte@Sun.COM if (!strategy) {
10137836SJohn.Forte@Sun.COM bp->b_flags |= B_ERROR;
10147836SJohn.Forte@Sun.COM bp->b_error = ENXIO;
10157836SJohn.Forte@Sun.COM (*bp->b_iodone)(bp);
10167836SJohn.Forte@Sun.COM } else
10177836SJohn.Forte@Sun.COM #ifdef DEBUG
10187836SJohn.Forte@Sun.COM /* inject i/o error for testing */
10197836SJohn.Forte@Sun.COM if (bp->b_error = _sdbc_ioj_lookup(bp->b_edev)) {
10207836SJohn.Forte@Sun.COM bp->b_flags |= B_ERROR;
10217836SJohn.Forte@Sun.COM (*bp->b_iodone)(bp);
10227836SJohn.Forte@Sun.COM } else
10237836SJohn.Forte@Sun.COM #endif
10247836SJohn.Forte@Sun.COM {
10257836SJohn.Forte@Sun.COM (*strategy)(bp);
10267836SJohn.Forte@Sun.COM }
10277836SJohn.Forte@Sun.COM } else {
10287836SJohn.Forte@Sun.COM (*bp->b_iodone)(bp);
10297836SJohn.Forte@Sun.COM }
10307836SJohn.Forte@Sun.COM
10317836SJohn.Forte@Sun.COM }
10327836SJohn.Forte@Sun.COM
10337836SJohn.Forte@Sun.COM #ifdef _SD_BIO_STATS
10347836SJohn.Forte@Sun.COM if (__start_io_count == 2000) {
10357836SJohn.Forte@Sun.COM __start_io_count = 0;
10367836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
10379093SRamana.Srikanth@Sun.COM "!sdbc(sd_start_io) t_bufs %d pages %d "
10387836SJohn.Forte@Sun.COM "combined %d norm %d norm_size %" NSC_SZFMT " skipped %d",
10397836SJohn.Forte@Sun.COM total_bufs,
10407836SJohn.Forte@Sun.COM total_pages, total_pages_combined, total_norm,
10417836SJohn.Forte@Sun.COM total_norm_size, total_skipped);
10427836SJohn.Forte@Sun.COM
10437836SJohn.Forte@Sun.COM total_bufs = 0;
10447836SJohn.Forte@Sun.COM total_pages = 0;
10457836SJohn.Forte@Sun.COM total_pages_combined = 0;
10467836SJohn.Forte@Sun.COM total_norm = 0;
10477836SJohn.Forte@Sun.COM total_norm_combined = 0;
10487836SJohn.Forte@Sun.COM total_skipped = 0;
10497836SJohn.Forte@Sun.COM total_norm_size = 0;
10507836SJohn.Forte@Sun.COM
10517836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
10529093SRamana.Srikanth@Sun.COM "!sdbc(sd_start_io)(r) max_run %d, total_xp %d total yp %d",
10537836SJohn.Forte@Sun.COM max_run_r, total_xpages_r, total_ypages_r);
10547836SJohn.Forte@Sun.COM
10557836SJohn.Forte@Sun.COM total_xpages_r = 0;
10567836SJohn.Forte@Sun.COM total_ypages_r = 0;
10577836SJohn.Forte@Sun.COM max_run_r = 0;
10587836SJohn.Forte@Sun.COM
10597836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
10609093SRamana.Srikanth@Sun.COM "!sdbc(sd_start_io)(w) max_run %d, total_xp %d total yp %d",
10617836SJohn.Forte@Sun.COM max_run_w, total_xpages_w, total_ypages_w);
10627836SJohn.Forte@Sun.COM
10637836SJohn.Forte@Sun.COM total_xpages_w = 0;
10647836SJohn.Forte@Sun.COM total_ypages_w = 0;
10657836SJohn.Forte@Sun.COM max_run_w = 0;
10667836SJohn.Forte@Sun.COM }
10677836SJohn.Forte@Sun.COM #endif /* _SD_BIO_STATS */
10687836SJohn.Forte@Sun.COM
10697836SJohn.Forte@Sun.COM if (ea_fn == _sd_async_ea) {
10707836SJohn.Forte@Sun.COM DTRACE_PROBE(sd_start_io_end);
10717836SJohn.Forte@Sun.COM
10727836SJohn.Forte@Sun.COM return (NSC_PENDING);
10737836SJohn.Forte@Sun.COM }
10747836SJohn.Forte@Sun.COM
10757836SJohn.Forte@Sun.COM mutex_enter(hook->lockp);
10767836SJohn.Forte@Sun.COM
10777836SJohn.Forte@Sun.COM while (hook->count) {
10787836SJohn.Forte@Sun.COM cv_wait(&hook->wait, hook->lockp);
10797836SJohn.Forte@Sun.COM }
10807836SJohn.Forte@Sun.COM mutex_exit(hook->lockp);
10817836SJohn.Forte@Sun.COM
10827836SJohn.Forte@Sun.COM err = hook->error ? hook->error : NSC_DONE;
10837836SJohn.Forte@Sun.COM bp = hook->tail;
10847836SJohn.Forte@Sun.COM _sd_put_hook(hook);
10857836SJohn.Forte@Sun.COM _sd_put_iobuf(bp);
10867836SJohn.Forte@Sun.COM
10877836SJohn.Forte@Sun.COM return (err);
10887836SJohn.Forte@Sun.COM }
10897836SJohn.Forte@Sun.COM
10907836SJohn.Forte@Sun.COM /*
10917836SJohn.Forte@Sun.COM * _sd_sync_ea - called when a single i/o operation is complete. If this
10927836SJohn.Forte@Sun.COM * is the last outstanding i/o we wakeup the sleeper.
10937836SJohn.Forte@Sun.COM * If this i/o had an error then we store the error result in the
10947836SJohn.Forte@Sun.COM * iob_hook if this was the first error.
10957836SJohn.Forte@Sun.COM *
10967836SJohn.Forte@Sun.COM * ARGUMENTS:
10977836SJohn.Forte@Sun.COM * bp - the struct buf describing the block i/o that just completed.
10987836SJohn.Forte@Sun.COM *
10997836SJohn.Forte@Sun.COM * Comments:
11007836SJohn.Forte@Sun.COM * This routine is called at interrupt level when the io is done.
11017836SJohn.Forte@Sun.COM */
11027836SJohn.Forte@Sun.COM
11037836SJohn.Forte@Sun.COM static int
_sd_sync_ea(struct buf * bp,iob_hook_t * hook)11047836SJohn.Forte@Sun.COM _sd_sync_ea(struct buf *bp, iob_hook_t *hook)
11057836SJohn.Forte@Sun.COM {
11067836SJohn.Forte@Sun.COM
11077836SJohn.Forte@Sun.COM int error;
11087836SJohn.Forte@Sun.COM int done;
11097836SJohn.Forte@Sun.COM
11107836SJohn.Forte@Sun.COM /*
11117836SJohn.Forte@Sun.COM * We get called for each buf that completes. When they are all done.
11127836SJohn.Forte@Sun.COM * we wakeup the waiter.
11137836SJohn.Forte@Sun.COM */
11147836SJohn.Forte@Sun.COM error = (bp->b_flags & B_ERROR) ? bp->b_error : 0;
11157836SJohn.Forte@Sun.COM
11167836SJohn.Forte@Sun.COM mutex_enter(hook->lockp);
11177836SJohn.Forte@Sun.COM
11187836SJohn.Forte@Sun.COM if (!hook->error)
11197836SJohn.Forte@Sun.COM hook->error = error;
11207836SJohn.Forte@Sun.COM
11217836SJohn.Forte@Sun.COM done = !(--hook->count);
11227836SJohn.Forte@Sun.COM if (done) {
11237836SJohn.Forte@Sun.COM /* remember the last buffer so we can free it later */
11247836SJohn.Forte@Sun.COM hook->tail = bp;
11257836SJohn.Forte@Sun.COM cv_signal(&hook->wait);
11267836SJohn.Forte@Sun.COM }
11277836SJohn.Forte@Sun.COM mutex_exit(hook->lockp);
11287836SJohn.Forte@Sun.COM
11297836SJohn.Forte@Sun.COM /*
11307836SJohn.Forte@Sun.COM * let sd_start_io free the final buffer so the hook can be returned
11317836SJohn.Forte@Sun.COM * first.
11327836SJohn.Forte@Sun.COM */
11337836SJohn.Forte@Sun.COM if (!done)
11347836SJohn.Forte@Sun.COM _sd_put_iobuf(bp);
11357836SJohn.Forte@Sun.COM
11367836SJohn.Forte@Sun.COM return (0);
11377836SJohn.Forte@Sun.COM }
11387836SJohn.Forte@Sun.COM
11397836SJohn.Forte@Sun.COM /*
11407836SJohn.Forte@Sun.COM * static int
11417836SJohn.Forte@Sun.COM * _sd_async_ea - End action for async read/write.
11427836SJohn.Forte@Sun.COM *
11437836SJohn.Forte@Sun.COM * ARGUMENTS:
11447836SJohn.Forte@Sun.COM * bp - io buf pointer.
11457836SJohn.Forte@Sun.COM *
11467836SJohn.Forte@Sun.COM * RETURNS:
11477836SJohn.Forte@Sun.COM * NONE.
11487836SJohn.Forte@Sun.COM *
11497836SJohn.Forte@Sun.COM * Comments:
11507836SJohn.Forte@Sun.COM * This routine is called at interrupt level when the io is done.
11517836SJohn.Forte@Sun.COM * This is only called when the operation is asynchronous.
11527836SJohn.Forte@Sun.COM */
11537836SJohn.Forte@Sun.COM static int
_sd_async_ea(struct buf * bp,iob_hook_t * hook)11547836SJohn.Forte@Sun.COM _sd_async_ea(struct buf *bp, iob_hook_t *hook)
11557836SJohn.Forte@Sun.COM {
11567836SJohn.Forte@Sun.COM int done, error;
11577836SJohn.Forte@Sun.COM
11587836SJohn.Forte@Sun.COM /*
11597836SJohn.Forte@Sun.COM * We get called for each buf that completes. When they are all done.
11607836SJohn.Forte@Sun.COM * we call the requestor's callback function.
11617836SJohn.Forte@Sun.COM */
11627836SJohn.Forte@Sun.COM error = (bp->b_flags & B_ERROR) ? bp->b_error : 0;
11637836SJohn.Forte@Sun.COM
11647836SJohn.Forte@Sun.COM mutex_enter(hook->lockp);
11657836SJohn.Forte@Sun.COM done = !(--hook->count);
11667836SJohn.Forte@Sun.COM
11677836SJohn.Forte@Sun.COM if (!hook->error)
11687836SJohn.Forte@Sun.COM hook->error = error;
11697836SJohn.Forte@Sun.COM
11707836SJohn.Forte@Sun.COM mutex_exit(hook->lockp);
11717836SJohn.Forte@Sun.COM
11727836SJohn.Forte@Sun.COM bp->b_forw = NULL;
11737836SJohn.Forte@Sun.COM bp->b_back = NULL;
11747836SJohn.Forte@Sun.COM
11757836SJohn.Forte@Sun.COM if (done) {
11767836SJohn.Forte@Sun.COM nsc_off_t fba_pos;
11777836SJohn.Forte@Sun.COM nsc_size_t fba_len;
11787836SJohn.Forte@Sun.COM int error;
11797836SJohn.Forte@Sun.COM sdbc_ea_fn_t fn;
11807836SJohn.Forte@Sun.COM blind_t arg;
11817836SJohn.Forte@Sun.COM
11827836SJohn.Forte@Sun.COM arg = hook->param;
11837836SJohn.Forte@Sun.COM fn = hook->func;
11847836SJohn.Forte@Sun.COM error = hook->error;
11857836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG) /* simulate disk errors */
11867836SJohn.Forte@Sun.COM if (_test_async_fail == bp->b_edev) error = EIO;
11877836SJohn.Forte@Sun.COM #endif
11887836SJohn.Forte@Sun.COM
11897836SJohn.Forte@Sun.COM /* MAKE SURE b_lblkno, b_count never changes!! */
11907836SJohn.Forte@Sun.COM fba_pos = hook->start_fba;
11917836SJohn.Forte@Sun.COM fba_len = FBA_LEN(hook->size);
11927836SJohn.Forte@Sun.COM
11937836SJohn.Forte@Sun.COM _sd_put_hook(hook);
11947836SJohn.Forte@Sun.COM _sd_put_iobuf(bp);
11957836SJohn.Forte@Sun.COM (*fn)(arg, fba_pos, fba_len, error);
11967836SJohn.Forte@Sun.COM } else
11977836SJohn.Forte@Sun.COM _sd_put_iobuf(bp);
11987836SJohn.Forte@Sun.COM
11997836SJohn.Forte@Sun.COM return (0);
12007836SJohn.Forte@Sun.COM }
12017836SJohn.Forte@Sun.COM
12027836SJohn.Forte@Sun.COM #ifdef DEBUG
12037836SJohn.Forte@Sun.COM typedef struct ioerr_inject_s {
12047836SJohn.Forte@Sun.COM dev_t ioj_dev;
12057836SJohn.Forte@Sun.COM int ioj_err;
12067836SJohn.Forte@Sun.COM int ioj_cnt;
12077836SJohn.Forte@Sun.COM } ioerr_inject_t;
12087836SJohn.Forte@Sun.COM
12097836SJohn.Forte@Sun.COM static ioerr_inject_t *ioerr_inject_table = NULL;
12107836SJohn.Forte@Sun.COM
12117836SJohn.Forte@Sun.COM void
_sdbc_ioj_load()12127836SJohn.Forte@Sun.COM _sdbc_ioj_load()
12137836SJohn.Forte@Sun.COM {
12147836SJohn.Forte@Sun.COM ioerr_inject_table =
12157836SJohn.Forte@Sun.COM kmem_zalloc(sdbc_max_devs * sizeof (ioerr_inject_t), KM_SLEEP);
12167836SJohn.Forte@Sun.COM }
12177836SJohn.Forte@Sun.COM
12187836SJohn.Forte@Sun.COM void
_sdbc_ioj_unload()12197836SJohn.Forte@Sun.COM _sdbc_ioj_unload()
12207836SJohn.Forte@Sun.COM {
12217836SJohn.Forte@Sun.COM if (ioerr_inject_table != NULL) {
12227836SJohn.Forte@Sun.COM kmem_free(ioerr_inject_table,
12237836SJohn.Forte@Sun.COM sdbc_max_devs * sizeof (ioerr_inject_t));
12247836SJohn.Forte@Sun.COM ioerr_inject_table = NULL;
12257836SJohn.Forte@Sun.COM }
12267836SJohn.Forte@Sun.COM }
12277836SJohn.Forte@Sun.COM
12287836SJohn.Forte@Sun.COM static int
_sdbc_ioj_lookup(dev_t dev)12297836SJohn.Forte@Sun.COM _sdbc_ioj_lookup(dev_t dev)
12307836SJohn.Forte@Sun.COM {
12317836SJohn.Forte@Sun.COM int cd;
12327836SJohn.Forte@Sun.COM
12337836SJohn.Forte@Sun.COM for (cd = 0; cd < sdbc_max_devs; ++cd)
12347836SJohn.Forte@Sun.COM if (ioerr_inject_table[cd].ioj_dev == dev) {
12357836SJohn.Forte@Sun.COM if (ioerr_inject_table[cd].ioj_cnt > 0) {
12367836SJohn.Forte@Sun.COM --ioerr_inject_table[cd].ioj_cnt;
12377836SJohn.Forte@Sun.COM return (0);
12387836SJohn.Forte@Sun.COM } else {
12397836SJohn.Forte@Sun.COM return (ioerr_inject_table[cd].ioj_err);
12407836SJohn.Forte@Sun.COM }
12417836SJohn.Forte@Sun.COM }
12427836SJohn.Forte@Sun.COM return (0);
12437836SJohn.Forte@Sun.COM }
12447836SJohn.Forte@Sun.COM
12457836SJohn.Forte@Sun.COM void
_sdbc_ioj_set_dev(int cd,dev_t crdev)12467836SJohn.Forte@Sun.COM _sdbc_ioj_set_dev(int cd, dev_t crdev)
12477836SJohn.Forte@Sun.COM {
12487836SJohn.Forte@Sun.COM int i;
12497836SJohn.Forte@Sun.COM
12507836SJohn.Forte@Sun.COM if (cd == -1) { /* all -- used for clearing table on shutdown */
12517836SJohn.Forte@Sun.COM for (i = 0; i < sdbc_max_devs; ++i) {
12527836SJohn.Forte@Sun.COM ioerr_inject_table[i].ioj_dev = crdev;
12537836SJohn.Forte@Sun.COM }
12547836SJohn.Forte@Sun.COM } else
12557836SJohn.Forte@Sun.COM ioerr_inject_table[cd].ioj_dev = crdev; /* assume valid cd */
12567836SJohn.Forte@Sun.COM }
12577836SJohn.Forte@Sun.COM
12587836SJohn.Forte@Sun.COM static
12597836SJohn.Forte@Sun.COM void
_sdbc_ioj_set_err(int cd,int err,int count)12607836SJohn.Forte@Sun.COM _sdbc_ioj_set_err(int cd, int err, int count)
12617836SJohn.Forte@Sun.COM {
12627836SJohn.Forte@Sun.COM int i;
12637836SJohn.Forte@Sun.COM
12647836SJohn.Forte@Sun.COM if (cd == -1) { /* all */
12657836SJohn.Forte@Sun.COM for (i = 0; i < sdbc_max_devs; ++i) {
12667836SJohn.Forte@Sun.COM ioerr_inject_table[i].ioj_err = err;
12677836SJohn.Forte@Sun.COM ioerr_inject_table[i].ioj_cnt = count;
12687836SJohn.Forte@Sun.COM }
12697836SJohn.Forte@Sun.COM } else {
12707836SJohn.Forte@Sun.COM ioerr_inject_table[cd].ioj_err = err;
12717836SJohn.Forte@Sun.COM ioerr_inject_table[cd].ioj_cnt = count;
12727836SJohn.Forte@Sun.COM }
12737836SJohn.Forte@Sun.COM }
12747836SJohn.Forte@Sun.COM
12757836SJohn.Forte@Sun.COM static void
_sdbc_ioj_clear_err(int cd)12767836SJohn.Forte@Sun.COM _sdbc_ioj_clear_err(int cd)
12777836SJohn.Forte@Sun.COM {
12787836SJohn.Forte@Sun.COM _sdbc_ioj_set_err(cd, 0, 0);
12797836SJohn.Forte@Sun.COM }
12807836SJohn.Forte@Sun.COM
12817836SJohn.Forte@Sun.COM int
_sdbc_inject_ioerr(int cd,int ioj_err,int count)12827836SJohn.Forte@Sun.COM _sdbc_inject_ioerr(int cd, int ioj_err, int count)
12837836SJohn.Forte@Sun.COM {
12847836SJohn.Forte@Sun.COM if ((cd < -1) || (cd >= sdbc_max_devs))
12857836SJohn.Forte@Sun.COM return (EINVAL);
12867836SJohn.Forte@Sun.COM
12877836SJohn.Forte@Sun.COM _sdbc_ioj_set_err(cd, ioj_err, count);
12887836SJohn.Forte@Sun.COM
12897836SJohn.Forte@Sun.COM return (0);
12907836SJohn.Forte@Sun.COM }
12917836SJohn.Forte@Sun.COM
12927836SJohn.Forte@Sun.COM int
_sdbc_clear_ioerr(int cd)12937836SJohn.Forte@Sun.COM _sdbc_clear_ioerr(int cd)
12947836SJohn.Forte@Sun.COM {
12957836SJohn.Forte@Sun.COM if ((cd < -1) || (cd >= sdbc_max_devs))
12967836SJohn.Forte@Sun.COM return (EINVAL);
12977836SJohn.Forte@Sun.COM
12987836SJohn.Forte@Sun.COM _sdbc_ioj_clear_err(cd);
12997836SJohn.Forte@Sun.COM
13007836SJohn.Forte@Sun.COM return (0);
13017836SJohn.Forte@Sun.COM }
13027836SJohn.Forte@Sun.COM #endif
1303