Home | History | Annotate | Download | only in diskomizer
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 #pragma ident	"@(#)daio_uscsi.c	1.13	09/05/26 SMI"
     23 
     24 /*
     25  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     26  * Use is subject to license terms.
     27  */
     28 
     29 #include <sys/types.h>
     30 #include <sys/scsi/impl/uscsi.h>
     31 #include <sys/scsi/generic/commands.h>
     32 #include <sys/scsi/impl/commands.h>
     33 #include <errno.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 #include <sys/stat.h>
     37 #include <fcntl.h>
     38 #include <stdlib.h>
     39 
     40 #include <diskomizer/daio_dev.h>
     41 #include <diskomizer/daio.h>
     42 #include <diskomizer/log.h>
     43 #include "findap.h"
     44 #include "daio_async.h"
     45 #include "args.h"
     46 
     47 #ifdef BIG_ENDIAN
     48 #define	CONV2INT(A) (A)
     49 #else
     50 #define	SWABB(X) (((0xff & (X)) << 8) | (0xff00 & (X)) >> 8)
     51 #define	SWABS(X) ((SWABB(0xffff & (X)) << 16) |\
     52 		SWABB((0xffff0000 & (X)) >> 16))
     53 #define	CONV2INT(A) SWABS(A)
     54 #endif
     55 
     56 #define	MAX_GROUP2OFF 0xffffffffLL
     57 
     58 /*
     59  * Group 4 Commands, Direct Access Devices
     60  *
     61  * The ifndef is required as on later releases these are or should be
     62  * in the header files.
     63  */
     64 #ifndef SCMD_READ_G4
     65 #define	SCMD_READ_G4		0x88
     66 #endif
     67 
     68 #ifndef SCMD_WRITE_G4
     69 #define	SCMD_WRITE_G4		0x8a
     70 #endif
     71 
     72 #ifndef SCMD_WRITE_VERIFY_G4
     73 #define	SCMD_WRITE_VERIFY_G4	0x8e
     74 #endif
     75 
     76 #ifndef FORMG4LONGADDR
     77 #define	FORMG4LONGADDR(cdb, addr) \
     78 	(cdb)->g4_addr3 = (addr) >> 56; \
     79 	(cdb)->g4_addr2 = ((addr) >> 48) & 0xFF; \
     80 	(cdb)->g4_addr1 = ((addr) >> 40) & 0xFF; \
     81 	(cdb)->g4_addr0 = ((addr) >> 32) & 0xFF; \
     82 	(cdb)->g4_addtl_cdb_data3 = ((addr) >> 24) & 0xFF; \
     83 	(cdb)->g4_addtl_cdb_data2 = ((addr) >> 16) & 0xFF; \
     84 	(cdb)->g4_addtl_cdb_data1 = ((addr) >> 8) & 0xFF; \
     85 	(cdb)->g4_addtl_cdb_data0 = (addr) & 0xFF
     86 #endif
     87 
     88 
     89 union lun_n_tag {
     90 	uchar_t data;
     91 	struct {
     92 #if defined(_BIT_FIELDS_LTOH)
     93 		uchar_t reladdr:1;
     94 		uchar_t bytchk:1;
     95 		uchar_t res:1;
     96 		uchar_t fua:1;
     97 		uchar_t dpo:1;
     98 		uchar_t lun:3;
     99 #elif defined(_BIT_FIELDS_HTOL)
    100 		uchar_t lun:3;
    101 		uchar_t dpo:1;
    102 		uchar_t fua:1;
    103 		uchar_t res:1;
    104 		uchar_t bytchk:1;
    105 		uchar_t reladdr:1;
    106 #else
    107 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
    108 #endif
    109 	} un;
    110 };
    111 
    112 struct timeout_vals {
    113 	uint16_t (*set_timeout)(struct timeout_vals *v);
    114 	int16_t min;
    115 	int16_t diff;
    116 };
    117 
    118 static union lun_n_tag wlun_n_tag;
    119 static union lun_n_tag rlun_n_tag;
    120 
    121 static int uscsi_open(const char *path, int oflag, mode_t mode);
    122 static int uscsi_close(int fd);
    123 static void *uscsi_read_disko_vtoc(int fd);
    124 static ssize_t uscsi_pread(int fildes, void *buf, size_t nbyte, off_t offset);
    125 static ssize_t uscsi_pwrite(int fildes, void *buf, size_t nbyte, off_t offset);
    126 static int daio_uscsi_write(int fildes, uchar_t *bufp, int bufs, off_t
    127 		offset, daio_result_t *resultp, struct daio_id *id);
    128 static int daio_uscsi_read(int fildes, uchar_t *bufp, int bufs, off_t
    129 		offset, daio_result_t *resultp, struct daio_id *id);
    130 static int nodev(int, int);
    131 
    132 struct daio_ops DAIO_OPS = {
    133 	daio_async_init,
    134 	daio_async_init_checker,
    135 	daio_async_get_checker,
    136 	findap,
    137 	(daio_open_t)uscsi_open,
    138 	uscsi_close,
    139 	unlink,
    140 	stat64,
    141 	fstat64,
    142 	ioctl,
    143 	ftruncate64,
    144 	nodev, /* drect io does not make sense for USCSI */
    145 	uscsi_read_disko_vtoc,
    146 	daio_async_pwrite,
    147 	daio_async_pread,
    148 	daio_uscsi_write,
    149 	daio_uscsi_read,
    150 	daio_async_status,
    151 	daio_async_start_time,
    152 	daio_async_end_time,
    153 	daio_async_wait,
    154 	daio_async_cancel,
    155 	daio_async_fini,
    156 	daio_dev_dd
    157 };
    158 
    159 struct uscsi_str {
    160 	void *handle;
    161 	uint_t v_sectorsz;
    162 	struct disko_partition part;
    163 };
    164 
    165 static struct uscsi_str *uscsi_state;
    166 static int maxfd = -1;
    167 
    168 static struct timeout_vals uscsi_read_timeout;
    169 static struct timeout_vals uscsi_write_timeout;
    170 static int8_t write_cmd1;
    171 static int8_t write_cmd4;
    172 static int8_t allow_bad_vtoc;
    173 static int8_t ignore_partitions = 0;
    174 ssize_t (*pwrite_func)(int fildes, void *bufp, size_t bufs,
    175 	off_t off) = uscsi_pwrite;
    176 ssize_t (*pread_func)(int fildes, void *bufp, size_t bufs,
    177 	off_t off) = uscsi_pread;
    178 
    179 static int
    180 nodev(int x, int b)
    181 {
    182 	return (0);
    183 }
    184 
    185 static uint16_t
    186 set_timeout_diff(struct timeout_vals *v)
    187 {
    188 	return (v->min + (lrand48() % v->diff));
    189 }
    190 
    191 static uint16_t
    192 set_timeout_no_diff(struct timeout_vals *v)
    193 {
    194 	return (v->min);
    195 }
    196 
    197 static void
    198 io_timeouts(const struct option_ops *ops, char *base_str,
    199 	struct timeout_vals *v)
    200 {
    201 	char *str;
    202 
    203 	if (ops->opt_short(base_str, &v->min) == OPT_OK) {
    204 		/* for comatability */
    205 		plog(LOG_NOTICE, "%s %d second%s\n",
    206 		    str, v->min, v->min == 1 ? "" : "s");
    207 		v->diff = 0;
    208 	} else if ((str = malloc(strlen(base_str) + 5)) != NULL) {
    209 		int16_t max;
    210 
    211 		sprintf(str, "%s.min", base_str);
    212 		if (ops->opt_short(str, &v->min) != OPT_OK) {
    213 			v->min = 60;
    214 		} else {
    215 			plog(LOG_NOTICE, "%s %d second%s\n",
    216 			    str, v->min, v->min == 1 ? "" : "s");
    217 		}
    218 		sprintf(str, "%s.max", base_str);
    219 		if (ops->opt_short(str, &max) != OPT_OK) {
    220 			max = 60;
    221 		} else {
    222 			plog(LOG_NOTICE, "%s %d second%s\n",
    223 			    str, max, max == 1 ? "" : "s");
    224 		}
    225 		if (max < v->min) {
    226 			plog(LOG_WARNING,
    227 			    "%s max (%d) less then min (%d)"
    228 			    " setting min to max\n", base_str, max, v->min);
    229 			v->min = max;
    230 			v->diff = 0;
    231 		} else {
    232 			v->diff = max - v->min;
    233 		}
    234 		free(str);
    235 	} else {
    236 		v->min = 60;
    237 		v->diff = 0;
    238 	}
    239 	if (v->diff == 0) {
    240 		v->set_timeout = set_timeout_no_diff;
    241 	} else {
    242 		v->set_timeout = set_timeout_diff;
    243 	}
    244 }
    245 
    246 static void
    247 uscsi_init(void)
    248 {
    249 	const struct option_ops *ops;
    250 	char x;
    251 
    252 	ops = opts_init();
    253 
    254 	plog(LOG_NOTICE, "DAIO_USCSI version %s\n", VERSION);
    255 
    256 	if (ops->opt_bool("DAIO_USCSI_IGNORE_PARTITIONS", &x) ==
    257 	    OPT_OK && x == 1) {
    258 		plog(LOG_NOTICE, "USCSI IGNORE_PARTITIONS on\n");
    259 		ignore_partitions = 1;
    260 	}
    261 
    262 	if (ops->opt_bool("DAIO_USCSI_USE_PWRITE", &x) == OPT_OK && x == 1) {
    263 		if (ignore_partitions) {
    264 			plog(LOG_ERR, "DAIO_USCSI_USE_PWRITE and "
    265 			    "DAIO_USCSI_IGNORE_PARTITIONS are mutually "
    266 			    "exclusive\n");
    267 			exit(1);
    268 		}
    269 		pwrite_func =
    270 		    (ssize_t (*)(int, void *, size_t, off_t)) pwrite64;
    271 	} else {
    272 
    273 		if (ops->opt_bool("DAIO_USCSI_WRITE_VERIFY", &x) == OPT_OK &&
    274 		    x == 1) {
    275 			write_cmd1 = SCMD_WRITE_VERIFY;
    276 			write_cmd4 = SCMD_WRITE_VERIFY_G4;
    277 			plog(LOG_NOTICE, "USCSI WRITE_VERIFY on\n");
    278 			if (ops->opt_bool("DAIO_USCSI_WRITE_VERIFY_BYTE_CHECK",
    279 			    &x) == OPT_OK && x == 1) {
    280 				plog(LOG_NOTICE,
    281 				    "USCSI WRITE VERIFY_BYTE_CHECK on\n");
    282 				wlun_n_tag.un.bytchk = 1;
    283 			}
    284 		} else {
    285 			write_cmd1 = SCMD_WRITE_G1;
    286 			write_cmd4 = SCMD_WRITE_G4;
    287 		}
    288 
    289 		if (ops->opt_bool("DAIO_USCSI_WRITE_FORCE_UNIT_ACCESS", &x) ==
    290 		    OPT_OK && x == 1) {
    291 			plog(LOG_NOTICE,
    292 			    "USCSI WRITE FORCE_UNIT_ACCESS on\n");
    293 			wlun_n_tag.un.fua = 1;
    294 		}
    295 
    296 		if (ops->opt_bool("DAIO_USCSI_WRITE_DISABLE_PAGE_OUT", &x) ==
    297 		    OPT_OK && x == 1) {
    298 			plog(LOG_NOTICE,
    299 			    "USCSI WRITE DISABLE_PAGE_OUT on\n");
    300 			wlun_n_tag.un.dpo = 1;
    301 		}
    302 
    303 		io_timeouts(ops, "DAIO_USCSI_WRITE_TIMEOUT",
    304 		    &uscsi_write_timeout);
    305 	}
    306 
    307 	if (ops->opt_bool("DAIO_USCSI_USE_PREAD", &x) == OPT_OK && x == 1) {
    308 		if (ignore_partitions) {
    309 			plog(LOG_ERR, "DAIO_USCSI_USE_PREAD and "
    310 			    "DAIO_USCSI_IGNORE_PARTITIONS are mutually "
    311 			    "exclusive\n");
    312 			exit(1);
    313 		}
    314 		pread_func = pread64;
    315 	} else {
    316 		if (ops->opt_bool("DAIO_USCSI_READ_FORCE_UNIT_ACCESS", &x) ==
    317 		    OPT_OK && x == 1) {
    318 			plog(LOG_NOTICE, "USCSI READ_UNIT_ACCESS on\n");
    319 			rlun_n_tag.un.fua = 1;
    320 		}
    321 
    322 		if (ops->opt_bool("DAIO_USCSI_READ_DISABLE_PAGE_OUT", &x) ==
    323 		    OPT_OK && x == 1) {
    324 			plog(LOG_NOTICE,
    325 			    "USCSI READ DISABLE_PAGE_OUT on\n");
    326 			rlun_n_tag.un.dpo = 1;
    327 		}
    328 
    329 		io_timeouts(ops, "DAIO_USCSI_READ_TIMEOUT",
    330 		    &uscsi_read_timeout);
    331 	}
    332 
    333 	if (ops->opt_bool("DAIO_USCSI_ALLOW_BAD_VTOC", &x) ==
    334 	    OPT_OK && x == 1) {
    335 		plog(LOG_NOTICE, "USCSI ALLOW_BAD_VTOC on\n");
    336 		allow_bad_vtoc = 1;
    337 	}
    338 
    339 	opts_fini();
    340 }
    341 
    342 static int
    343 uscsi_read_capacity(int fildes, uint32_t *bs, uint64_t *mba)
    344 {
    345 	struct uscsi_cmd ucmd;
    346 	union scsi_cdb cdb;
    347 	struct buf {
    348 		uint32_t mba;
    349 		uint32_t bs;
    350 	} buf;
    351 
    352 	memset(&ucmd, 0, sizeof (struct uscsi_cmd));
    353 	memset(&cdb, 0, sizeof (cdb));
    354 	memset(&buf, 0, sizeof (buf));
    355 
    356 	cdb.scc_cmd = SCMD_READ_CAPACITY;
    357 	ucmd.uscsi_cdblen = CDB_GROUP1;
    358 	ucmd.uscsi_flags = USCSI_READ;
    359 	ucmd.uscsi_cdb = (char *)&cdb;
    360 	ucmd.uscsi_bufaddr = (void *)&buf;
    361 	ucmd.uscsi_buflen = sizeof (buf);
    362 	ucmd.uscsi_resid = sizeof (buf);
    363 
    364 	if (ioctl(fildes, USCSICMD, &ucmd) == -1) {
    365 		return (-1);
    366 	}
    367 
    368 	if (ucmd.uscsi_status != 0) {
    369 		errno = EIO;
    370 		return (-1);
    371 	}
    372 	*bs = CONV2INT(buf.bs);
    373 	*mba = CONV2INT(buf.mba);
    374 
    375 	return (ucmd.uscsi_resid);
    376 }
    377 
    378 static int
    379 uscsi_open(const char *path, int oflag, mode_t mode)
    380 {
    381 	int fd;
    382 	if (uscsi_read_timeout.min == 0 && uscsi_read_timeout.diff == 0) {
    383 		uscsi_init();
    384 	}
    385 
    386 	if ((fd = daio_dev_open(path, oflag, mode)) == -1) {
    387 		return (-1);
    388 	}
    389 	if (fd > maxfd) {
    390 		struct uscsi_str *tmp;
    391 
    392 		tmp = realloc(uscsi_state, (fd+1) * sizeof (struct uscsi_str));
    393 		if (tmp == NULL) {
    394 			daio_dev_close(fd);
    395 			errno = ENOMEM;
    396 			return (-1);
    397 		}
    398 		memset(&tmp[maxfd+1], 0,
    399 		    (fd - maxfd) * sizeof (struct uscsi_str));
    400 		uscsi_state = tmp;
    401 		maxfd = fd;
    402 	}
    403 	uscsi_state[fd].handle = uscsi_read_disko_vtoc(fd);
    404 	plog(LOG_NOTICE, "USCSI %s\n", path);
    405 	plog(LOG_NOTICE, "USCSI sector size %d disk size %ld\n",
    406 	    uscsi_state[fd].v_sectorsz, uscsi_state[fd].part.p_size);
    407 	return (fd);
    408 }
    409 
    410 static int
    411 uscsi_close(int fd)
    412 {
    413 	if (uscsi_state[fd].handle) {
    414 		disko_vtoc_free(uscsi_state[fd].handle);
    415 	}
    416 	memset(&uscsi_state[fd], 0, sizeof (uscsi_state[fd]));
    417 	return (daio_dev_close(fd));
    418 }
    419 
    420 static struct disko_vtoc *
    421 uscsi_read_capacity_vtoc(int fd)
    422 {
    423 	struct disko_vtoc *dv;
    424 
    425 	if ((dv = alloc_disko_vtoc(1)) == NULL) {
    426 		return (NULL);
    427 	}
    428 	memset(&dv->v_volume[0], 0, sizeof (dv->v_volume));
    429 	memset(&dv->v_asciilabel[0], 0, sizeof (dv->v_asciilabel));
    430 
    431 	uscsi_state[fd].part.p_start = 0;
    432 	dv->v_sectorsz = uscsi_state[fd].v_sectorsz;
    433 	dv->v_nparts = 1;
    434 	dv->this_part = 0;
    435 	dv->v_part[0] = uscsi_state[fd].part;
    436 	plog(LOG_NOTICE, "USCSI read_capacity: file %s",
    437 	    daio_dev_path(fd));
    438 	plog(LOG_NOTICE, "USCSI read_capacity: "
    439 	    "Number of sectors %lld sector size %d\n",
    440 	    uscsi_state[fd].part.p_size, uscsi_state[fd].v_sectorsz);
    441 	return (dv);
    442 }
    443 
    444 static void *
    445 uscsi_read_disko_vtoc(int fd)
    446 {
    447 	void *handle;
    448 
    449 	if ((handle = uscsi_state[fd].handle) != NULL) {
    450 		/*
    451 		 * We are no longer in cotrol of the memory associated with
    452 		 * the handle. It will be freed by the caller so drop our
    453 		 * copy of it. If we were to need the vtoc from the disk
    454 		 * again we can get it from the disk.
    455 		 *
    456 		 * In practice we don't.
    457 		 */
    458 		uscsi_state[fd].handle = NULL;
    459 		return (handle);
    460 	}
    461 	if (ignore_partitions) {
    462 		return (uscsi_read_capacity_vtoc(fd));
    463 	}
    464 
    465 	if ((handle = read_disko_vtoc(fd)) == NULL) {
    466 		struct disko_vtoc *dv;
    467 		if (!allow_bad_vtoc) {
    468 			return (NULL);
    469 		}
    470 		return (uscsi_read_capacity_vtoc(fd));
    471 	}
    472 	uscsi_state[fd].v_sectorsz = disko_vtoc_sectorsz(handle);
    473 	uscsi_state[fd].part = *disko_vtoc_this_partition(handle);
    474 	return (handle);
    475 }
    476 
    477 static ssize_t
    478 uscsi_prw(int fildes, void *buf, size_t nbyte, off_t offset, int cmd)
    479 {
    480 	struct uscsi_cmd ucmd;
    481 	uint64_t lba;
    482 	uint32_t len;
    483 	union scsi_cdb cdb;
    484 
    485 	if (nbyte % uscsi_state[fildes].v_sectorsz != 0 ||
    486 	    offset % uscsi_state[fildes].v_sectorsz != 0) {
    487 		plog(LOG_ERR,
    488 		    "USCSI io at 0x%llx length 0x%x to file %s not aligned "
    489 		    "with 0x%x\n",
    490 		    offset, nbyte, daio_dev_path(fildes),
    491 		    uscsi_state[fildes].v_sectorsz);
    492 		errno = EINVAL;
    493 		return (-1);
    494 	}
    495 	lba = offset/uscsi_state[fildes].v_sectorsz;
    496 	len = nbyte/uscsi_state[fildes].v_sectorsz;
    497 
    498 	if (!ignore_partitions) {
    499 		if (lba + len > uscsi_state[fildes].part.p_size) {
    500 			errno = ENXIO;
    501 			return (-1);
    502 		}
    503 		lba += uscsi_state[fildes].part.p_start;
    504 	}
    505 	if (len > 256) {
    506 		plog(LOG_ERR,
    507 		    "USCSI io at %lld length %d (%d) to file %s to big "
    508 		    "for bs %d\n",
    509 		    offset, nbyte, len, daio_dev_path(fildes),
    510 		    uscsi_state[fildes].v_sectorsz);
    511 		errno = EINVAL;
    512 		return (-1);
    513 	}
    514 
    515 	memset(&ucmd, 0, sizeof (struct uscsi_cmd));
    516 	memset(&cdb, 0, sizeof (cdb));
    517 
    518 	if (cmd == USCSI_READ) {
    519 		if (lba > MAX_GROUP2OFF) {
    520 			cdb.scc_cmd = SCMD_READ_G4;
    521 		} else {
    522 			cdb.scc_cmd = SCMD_READ_G1;
    523 		}
    524 		cdb.scc_lun = rlun_n_tag.data;
    525 		ucmd.uscsi_timeout =
    526 		    uscsi_read_timeout.set_timeout(&uscsi_read_timeout);
    527 	} else {
    528 		if (lba > MAX_GROUP2OFF) {
    529 			cdb.scc_cmd = write_cmd4;
    530 		} else {
    531 			cdb.scc_cmd = write_cmd1;
    532 		}
    533 		cdb.scc_lun = wlun_n_tag.data;
    534 		ucmd.uscsi_timeout =
    535 		    uscsi_write_timeout.set_timeout(&uscsi_write_timeout);
    536 	}
    537 
    538 	if (lba > MAX_GROUP2OFF) {
    539 		FORMG4LONGADDR(&cdb, lba);
    540 		FORMG4COUNT(&cdb, len);
    541 		ucmd.uscsi_cdblen = CDB_GROUP4;
    542 	} else {
    543 		uint32_t lba32 = (uint32_t)lba;
    544 		FORMG1ADDR(&cdb, lba32);
    545 		FORMG1COUNT(&cdb, len);
    546 		ucmd.uscsi_cdblen = CDB_GROUP1;
    547 	}
    548 	ucmd.uscsi_flags = cmd;
    549 	ucmd.uscsi_cdb = (char *)&cdb;
    550 	ucmd.uscsi_bufaddr = buf;
    551 	ucmd.uscsi_buflen = nbyte;
    552 	ucmd.uscsi_resid = nbyte;
    553 
    554 	if (ioctl(fildes, USCSICMD, &ucmd) == -1) {
    555 		return (-1);
    556 	}
    557 
    558 	if (ucmd.uscsi_status != 0) {
    559 		plog(LOG_ERR,
    560 		    "USCSI io at %x length %x to file %s status %d\n",
    561 		    offset, nbyte, daio_dev_path(fildes),
    562 		    ucmd.uscsi_status);
    563 		errno = EIO;
    564 		return (-1);
    565 	}
    566 
    567 	if (ucmd.uscsi_resid) {
    568 		plog(LOG_ERR, "nbyte %d ucmd.uscsi_resid %d\n",
    569 		    nbyte, ucmd.uscsi_resid);
    570 	}
    571 	errno = 0;
    572 	return (nbyte - ucmd.uscsi_resid);
    573 }
    574 
    575 static ssize_t
    576 uscsi_pread(int fildes, void *buf, size_t nbyte, off_t offset)
    577 {
    578 	return (uscsi_prw(fildes, buf, nbyte, offset, USCSI_READ));
    579 }
    580 
    581 static ssize_t
    582 uscsi_pwrite(int fildes, void *buf, size_t nbyte, off_t offset)
    583 {
    584 	return (uscsi_prw(fildes, buf, nbyte, offset, USCSI_WRITE));
    585 }
    586 
    587 static int
    588 daio_uscsi_read(int fildes, uchar_t *bufp, int bufs, off_t offset,
    589 	daio_result_t *resultp, struct daio_id *id)
    590 {
    591 	return (daio_async_rw(fildes, bufp, bufs, offset, resultp, id,
    592 	    pread_func, IS_READ));
    593 }
    594 static int
    595 daio_uscsi_write(int fildes, uchar_t *bufp, int bufs, off_t offset,
    596 	daio_result_t *resultp, struct daio_id *id)
    597 {
    598 	return (daio_async_rw(fildes, bufp, bufs, offset, resultp, id,
    599 	    pwrite_func, IS_WRITE));
    600 }
    601