diff --git a/share/examples/scsi_target/Makefile b/share/examples/scsi_target/Makefile
index 480da7a..bab70b2 100644
--- a/share/examples/scsi_target/Makefile
+++ b/share/examples/scsi_target/Makefile
@@ -1,10 +1,9 @@
-# $FreeBSD: src/share/examples/scsi_target/Makefile,v 1.2.2.1 2003/02/18 22:07:10 njl Exp $
-# $DragonFly: src/share/examples/scsi_target/Makefile,v 1.2 2003/06/17 04:36:57 dillon Exp $
+# $FreeBSD$
 
 PROG=	scsi_target
 SRCS=	scsi_target.h scsi_target.c scsi_cmds.c
-DPADD=	${LIBCAM}
-LDADD=	-lcam
+DPADD=	${LIBCAM} ${LIBSBUF}
+LDADD=	-lcam -lsbuf
 
 MAN=	scsi_target.8
 
diff --git a/share/examples/scsi_target/scsi_cmds.c b/share/examples/scsi_target/scsi_cmds.c
index a37b71b..c9d135e 100644
--- a/share/examples/scsi_target/scsi_cmds.c
+++ b/share/examples/scsi_target/scsi_cmds.c
@@ -25,17 +25,18 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/share/examples/scsi_target/scsi_cmds.c,v 1.2.2.1 2003/02/18 22:07:10 njl Exp $
- * $DragonFly: src/share/examples/scsi_target/scsi_cmds.c,v 1.2 2003/06/17 04:36:57 dillon Exp $
  */
 
 #include <stdio.h>
 #include <stddef.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include <err.h>
 #include <aio.h>
+#include <unistd.h>
 #include <assert.h>
+#include <sys/param.h>
 #include <sys/types.h>
 
 #include <cam/cam.h>
@@ -47,6 +48,9 @@
 typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *);
 typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *,
 			      io_ops);
+#ifndef	REPORT_LUNS
+#define	REPORT_LUNS	0xa0
+#endif
 
 struct targ_cdb_handlers {
 	u_int8_t	  cmd;
@@ -58,6 +62,9 @@ struct targ_cdb_handlers {
 static targ_start_func		tcmd_inquiry;
 static targ_start_func		tcmd_req_sense;
 static targ_start_func		tcmd_rd_cap;
+#ifdef READ_16
+static targ_start_func		tcmd_rd_cap16;
+#endif
 static targ_start_func		tcmd_rdwr;
 static targ_start_func		tcmd_rdwr_decode;
 static targ_done_func		tcmd_rdwr_done;
@@ -83,13 +90,19 @@ static struct targ_cdb_handlers cdb_handlers[] = {
 	{ SYNCHRONIZE_CACHE,	tcmd_null_ok,		NULL },
 	{ MODE_SENSE_6,		tcmd_illegal_req,	NULL },
 	{ MODE_SELECT_6,	tcmd_illegal_req,	NULL },
+	{ REPORT_LUNS,		tcmd_illegal_req,	NULL },
+#ifdef READ_16
+	{ READ_16,		tcmd_rdwr,		tcmd_rdwr_done },
+	{ WRITE_16,		tcmd_rdwr,		tcmd_rdwr_done },
+	{ SERVICE_ACTION_IN,	tcmd_rd_cap16,		NULL },
+#endif
 	{ ILLEGAL_CDB,		NULL,			NULL }
 };
 
 static struct scsi_inquiry_data inq_data;
 static struct initiator_state istates[MAX_INITIATORS];
 extern int		debug;
-extern u_int32_t	volume_size;
+extern uint64_t		volume_size;
 extern size_t		sector_size;
 extern size_t		buf_size;
 
@@ -142,6 +155,16 @@ tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
 		}
 		last_cmd = h;
 	}
+
+	/* call completion and exit */
+	if (event != ATIO_WORK) {
+		if (last_cmd->done != NULL)
+			last_cmd->done(atio, ctio, event);
+		else
+			free_ccb((union ccb *)ctio);
+		return (1);
+	}
+
 	if (last_cmd->cmd == ILLEGAL_CDB) {
 		if (event != ATIO_WORK) {
 			warnx("no done func for %#x???", a_descr->cdb[0]);
@@ -154,15 +177,6 @@ tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
 		return (0);
 	}
 
-	/* call completion and exit */
-	if (event != ATIO_WORK) {
-		if (last_cmd->done != NULL)
-			last_cmd->done(atio, ctio, event);
-		else
-			free_ccb((union ccb *)ctio);
-		return (1);
-	}
-
 	istate = tcmd_get_istate(ctio->init_id);
 	if (istate == NULL) {
 		tcmd_illegal_req(atio, ctio);
@@ -246,12 +260,10 @@ tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags,
 
 	/* Fill out the supplied CTIO */
 	if (ctio != NULL) {
-		/* No autosense yet
 		bcopy(sense, &ctio->sense_data, sizeof(*sense));
-		ctio->sense_len = sizeof(*sense);  XXX
-		*/
+		ctio->sense_len = sizeof(*sense);  /* XXX */
 		ctio->ccb_h.flags &= ~CAM_DIR_MASK;
-		ctio->ccb_h.flags |= CAM_DIR_NONE | /* CAM_SEND_SENSE | */
+		ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE |
 				     CAM_SEND_STATUS;
 		ctio->dxfer_len = 0;
 		ctio->scsi_status = SCSI_STATUS_CHECK_COND;
@@ -331,7 +343,11 @@ init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
 	inq = &inq_data;
 	bzero(inq, sizeof(*inq));
 	inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5);
+#ifdef SCSI_REV_SPC
+	inq->version = SCSI_REV_SPC; /* was 2 */
+#else
 	inq->version = SCSI_REV_3; /* was 2 */
+#endif
 
 	/*
 	 * XXX cpi.hba_inquiry doesn't support Addr16 so we give the
@@ -344,7 +360,7 @@ init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
 
 	/* Advertise only what the SIM can actually support */
 	req_flags &= sim_flags;
-	scsi_ulto2b(req_flags, &inq->reserved[1]);
+	scsi_ulto2b(req_flags, &inq->spc2_flags);
 
 	inq->response_format = 2; /* SCSI2 Inquiry Format */
 	inq->additional_length = SHORT_INQUIRY_LENGTH -
@@ -396,17 +412,55 @@ tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 {
 	struct scsi_read_capacity_data *srp;
 	struct atio_descr *a_descr;
+	uint32_t vsize;
 
 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
 	srp = (struct scsi_read_capacity_data *)ctio->data_ptr;
 
+	if (volume_size > 0xffffffff)
+		vsize = 0xffffffff;
+	else
+		vsize = (uint32_t)(volume_size - 1);
+
 	if (debug) {
 		cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ",
+			  atio->init_id, vsize, sector_size);
+	}
+
+	bzero(srp, sizeof(*srp));
+	scsi_ulto4b(vsize, srp->addr);
+	scsi_ulto4b(sector_size, srp->length);
+
+	ctio->dxfer_len = sizeof(*srp);
+	ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
+	ctio->scsi_status = SCSI_STATUS_OK;
+	return (0);
+}
+
+#ifdef READ_16
+static int
+tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+	struct scsi_read_capacity_16 *scsi_cmd;
+	struct scsi_read_capacity_data_long *srp;
+	struct atio_descr *a_descr;
+
+	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+	scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb;
+	srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr;
+
+	if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) {
+		tcmd_illegal_req(atio, ctio);
+		return (0);
+	}
+
+	if (debug) {
+		cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ",
 			  atio->init_id, volume_size - 1, sector_size);
 	}
 
 	bzero(srp, sizeof(*srp));
-	scsi_ulto4b(volume_size - 1, srp->addr);
+	scsi_u64to8b(volume_size - 1, srp->addr);
 	scsi_ulto4b(sector_size, srp->length);
 
 	ctio->dxfer_len = sizeof(*srp);
@@ -414,6 +468,7 @@ tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 	ctio->scsi_status = SCSI_STATUS_OK;
 	return (0);
 }
+#endif
 
 static int
 tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
@@ -441,13 +496,13 @@ tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 	if ((a_descr->flags & CAM_DIR_IN) != 0) {
 		ret = start_io(atio, ctio, CAM_DIR_IN);
 		if (debug)
-			warnx("Starting DIR_IN @%lld:%u", c_descr->offset,
-			      a_descr->targ_req);
+			warnx("Starting %p DIR_IN @" OFF_FMT ":%u",
+			    a_descr, c_descr->offset, a_descr->targ_req);
 	} else {
 		ret = start_io(atio, ctio, CAM_DIR_OUT);
 		if (debug)
-			warnx("Starting DIR_OUT @%lld:%u", c_descr->offset,
-			      a_descr->init_req);
+			warnx("Starting %p DIR_OUT @" OFF_FMT ":%u",
+			    a_descr, c_descr->offset, a_descr->init_req);
 	}
 
 	return (ret);
@@ -456,7 +511,8 @@ tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 static int
 tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 {
-	u_int32_t blkno, count;
+	uint64_t blkno;
+	uint32_t count;
 	struct atio_descr *a_descr;
 	u_int8_t *cdb;
 
@@ -465,14 +521,36 @@ tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 	if (debug)
 		cdb_debug(cdb, "R/W from %u: ", atio->init_id);
 
-	if (cdb[0] == READ_6 || cdb[0] == WRITE_6) {
+	switch (cdb[0]) {
+	case READ_6:
+	case WRITE_6:
+	{
 		struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb;
 		blkno = scsi_3btoul(rw_6->addr);
 		count = rw_6->length;
-	} else {
+		break;
+	}
+	case READ_10:
+	case WRITE_10:
+	{
 		struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb;
 		blkno = scsi_4btoul(rw_10->addr);
 		count = scsi_2btoul(rw_10->length);
+		break;
+	}
+#ifdef READ_16
+	case READ_16:
+	case WRITE_16:
+	{
+		struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb;
+		blkno = scsi_8btou64(rw_16->addr);
+		count = scsi_4btoul(rw_16->length);
+		break;
+	}
+#endif
+	default:
+		tcmd_illegal_req(atio, ctio);
+		return (0);
 	}
 	if (blkno + count > volume_size) {
 		warnx("Attempt to access past end of volume");
@@ -486,17 +564,17 @@ tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
 	a_descr->total_len = count * sector_size;
 	if (a_descr->total_len == 0) {
 		if (debug)
-			warnx("r/w 0 blocks @ blkno %u", blkno);
+			warnx("r/w 0 blocks @ blkno " OFF_FMT, blkno);
 		tcmd_null_ok(atio, ctio);
 		return (0);
 	} else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) {
 		a_descr->flags |= CAM_DIR_OUT;
 		if (debug)
-			warnx("write %u blocks @ blkno %u", count, blkno);
+			warnx("write %u blocks @ blkno " OFF_FMT, count, blkno);
 	} else {
 		a_descr->flags |= CAM_DIR_IN;
 		if (debug)
-			warnx("read %u blocks @ blkno %u", count, blkno);
+			warnx("read %u blocks @ blkno " OFF_FMT,  count, blkno);
 	}
 	return (1);
 }
@@ -528,14 +606,41 @@ start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir)
 	/* If DIR_IN, start read from target, otherwise begin CTIO xfer. */
 	ret = 1;
 	if (dir == CAM_DIR_IN) {
-		if (aio_read(&c_descr->aiocb) < 0)
-			err(1, "aio_read"); /* XXX */
+		if (notaio) {
+			if (debug)
+				warnx("read sync %lud @ block " OFF_FMT,
+				    (unsigned long)
+				    (ctio->dxfer_len / sector_size),
+				    c_descr->offset / sector_size);
+			if (lseek(c_descr->aiocb.aio_fildes,
+			    c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
+				perror("lseek");
+				err(1, "lseek");
+			}
+			if (read(c_descr->aiocb.aio_fildes,
+			    (void *)c_descr->aiocb.aio_buf,
+			    ctio->dxfer_len) != ctio->dxfer_len) {
+				err(1, "read");
+			}
+		} else {
+			if (debug)
+				warnx("read async %lud @ block " OFF_FMT,
+				    (unsigned long)
+				    (ctio->dxfer_len / sector_size),
+				    c_descr->offset / sector_size);
+			if (aio_read(&c_descr->aiocb) < 0) {
+				err(1, "aio_read"); /* XXX */
+			}
+		}
 		a_descr->targ_req += ctio->dxfer_len;
+		/* if we're done, we can mark the CCB as to send status */
 		if (a_descr->targ_req == a_descr->total_len) {
 			ctio->ccb_h.flags |= CAM_SEND_STATUS;
 			ctio->scsi_status = SCSI_STATUS_OK;
 			ret = 0;
 		}
+		if (notaio)
+			tcmd_rdwr_done(atio, ctio, AIO_DONE);
 	} else {
 		if (a_descr->targ_ack == a_descr->total_len)
 			tcmd_null_ok(atio, ctio);
@@ -567,7 +672,7 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
 
 	switch (event) {
 	case AIO_DONE:
-		if (aio_return(&c_descr->aiocb) < 0) {
+		if (!notaio && aio_return(&c_descr->aiocb) < 0) {
 			warn("aio_return error");
 			/* XXX */
 			tcmd_sense(ctio->init_id, ctio,
@@ -577,8 +682,12 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
 		}
 		a_descr->targ_ack += ctio->dxfer_len;
 		if ((a_descr->flags & CAM_DIR_IN) != 0) {
-			if (debug)
-				warnx("sending CTIO for AIO read");
+			if (debug) {
+				if (notaio)
+					warnx("sending CTIO for AIO read");
+				else
+					warnx("sending CTIO for sync read");
+			}
 			a_descr->init_req += ctio->dxfer_len;
 			send_ccb((union ccb *)ctio, /*priority*/1);
 		} else {
@@ -591,18 +700,55 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
 		}
 		break;
 	case CTIO_DONE:
-		if (ctio->ccb_h.status != CAM_REQ_CMP) {
-			/* XXX */
+		switch (ctio->ccb_h.status & CAM_STATUS_MASK) {
+		case CAM_REQ_CMP:
+			break;
+		case CAM_REQUEUE_REQ:
+			warnx("requeueing request");
+			if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
+				if (aio_write(&c_descr->aiocb) < 0) {
+					err(1, "aio_write"); /* XXX */
+				}
+			} else {
+				if (aio_read(&c_descr->aiocb) < 0) {
+					err(1, "aio_read"); /* XXX */
+				}
+			}
+			return;
+		default:
 			errx(1, "CTIO failed, status %#x", ctio->ccb_h.status);
 		}
 		a_descr->init_ack += ctio->dxfer_len;
 		if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT &&
 		    ctio->dxfer_len > 0) {
-			if (debug)
-				warnx("sending AIO for CTIO write");
 			a_descr->targ_req += ctio->dxfer_len;
-			if (aio_write(&c_descr->aiocb) < 0)
-				err(1, "aio_write"); /* XXX */
+			if (notaio) {
+				if (debug)
+					warnx("write sync %lud @ block "
+					    OFF_FMT, (unsigned long)
+					    (ctio->dxfer_len / sector_size),
+					    c_descr->offset / sector_size);
+				if (lseek(c_descr->aiocb.aio_fildes,
+				    c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
+					perror("lseek");
+					err(1, "lseek");
+				}
+				if (write(c_descr->aiocb.aio_fildes,
+				    (void *) c_descr->aiocb.aio_buf,
+				    ctio->dxfer_len) != ctio->dxfer_len) {
+					err(1, "write");
+				}
+				tcmd_rdwr_done(atio, ctio, AIO_DONE);
+			} else {
+				if (debug)
+					warnx("write async %lud @ block "
+					    OFF_FMT, (unsigned long)
+					    (ctio->dxfer_len / sector_size),
+					    c_descr->offset / sector_size);
+				if (aio_write(&c_descr->aiocb) < 0) {
+					err(1, "aio_write"); /* XXX */
+				}
+			}
 		} else {
 			if (debug)
 				warnx("CTIO done freeing CTIO");
diff --git a/share/examples/scsi_target/scsi_target.8 b/share/examples/scsi_target/scsi_target.8
index 9c76b2d..677e2b4 100644
--- a/share/examples/scsi_target/scsi_target.8
+++ b/share/examples/scsi_target/scsi_target.8
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/share/examples/scsi_target/scsi_target.8,v 1.2.4.1 2003/02/18 22:07:10 njl Exp $
+.\" $FreeBSD$
 .\"
 .Dd November 15, 2002
 .Dt SCSI_TARGET 8
@@ -94,6 +94,17 @@ and its associated control device.
 Use a different size for the emulated volume.
 Must be less than or equal to the size of
 .Ar filename .
+If the number ends with a
+.Dq Li k ,
+.Dq Li m ,
+.Dq Li g ,
+.Dq Li t ,
+.Dq Li p ,
+or
+.Dq Li e ,
+the number is multiplied by 2^10 (1K), 2^20 (1M), 2^30 (1G), 2^40 (1T),
+2^50 (1P) and 2^60 (1E)
+respectively.
 .El
 .Pp
 Required arguments:
@@ -129,7 +140,7 @@ will be used.
 Debugging information will be output.
 16-bit wide transfers will be used if the SIM supports them.
 .Pp
-.Dl "scsi_target -d -v 1000 -W 16 0:1:0 vol"
+.Dl "scsi_target -d -s 1000 -W 16 0:1:0 vol"
 .Sh SEE ALSO
 .Xr scsi 4 ,
 .Xr targ 4
@@ -144,4 +155,4 @@ and was written by
 It was rewritten for
 .Fx 5.0
 by
-.An Nate Lawson Aq Mt nate@root.org .
+.An Nate Lawson Aq nate@root.org .
diff --git a/share/examples/scsi_target/scsi_target.c b/share/examples/scsi_target/scsi_target.c
index 5867fc0..b57d084 100644
--- a/share/examples/scsi_target/scsi_target.c
+++ b/share/examples/scsi_target/scsi_target.c
@@ -25,11 +25,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/share/examples/scsi_target/scsi_target.c,v 1.5.2.5 2003/02/18 22:07:10 njl Exp $
- * $DragonFly: src/share/examples/scsi_target/scsi_target.c,v 1.2 2003/06/17 04:36:57 dillon Exp $
+ * $FreeBSD$
  */
 
 #include <sys/types.h>
+#include <ctype.h>
 #include <errno.h>
 #include <err.h>
 #include <fcntl.h>
@@ -55,14 +55,15 @@
 /* Maximum amount to transfer per CTIO */
 #define MAX_XFER	MAXPHYS
 /* Maximum number of allocated CTIOs */
-#define MAX_CTIOS	32
+#define MAX_CTIOS	64
 /* Maximum sector size for emulated volume */
 #define MAX_SECTOR	32768
 
 /* Global variables */
 int		debug;
-u_int32_t	volume_size;
-size_t		sector_size;
+int		notaio = 0;
+off_t		volume_size;
+u_int		sector_size;
 size_t		buf_size;
 
 /* Local variables */
@@ -85,7 +86,7 @@ static void		request_loop(void);
 static void		handle_read(void);
 /* static int		work_atio(struct ccb_accept_tio *); */
 static void		queue_io(struct ccb_scsiio *);
-static void		run_queue(struct ccb_accept_tio *);
+static int		run_queue(struct ccb_accept_tio *);
 static int		work_inot(struct ccb_immed_notify *);
 static struct ccb_scsiio *
 			get_ctio(void);
@@ -116,7 +117,7 @@ main(int argc, char *argv[])
 	TAILQ_INIT(&pending_queue);
 	TAILQ_INIT(&work_queue);
 
-	while ((ch = getopt(argc, argv, "AdSTb:c:s:W:")) != -1) {
+	while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) {
 		switch(ch) {
 		case 'A':
 			req_flags |= SID_Addr16;
@@ -141,10 +142,39 @@ main(int argc, char *argv[])
 				errx(1, "Unreasonable sector size: %s", optarg);
 			break;
 		case 's':
-			user_size = strtoll(optarg, NULL, /*base*/10);
+		{
+			int last, shift = 0;
+
+			last = strlen(optarg) - 1;
+			if (last > 0) {
+				switch (tolower(optarg[last])) {
+				case 'e':
+					shift += 10;
+					/* FALLTHROUGH */
+				case 'p':
+					shift += 10;
+					/* FALLTHROUGH */
+				case 't':
+					shift += 10;
+					/* FALLTHROUGH */
+				case 'g':
+					shift += 10;
+					/* FALLTHROUGH */
+				case 'm':
+					shift += 10;
+					/* FALLTHROUGH */
+				case 'k':
+					shift += 10;
+					optarg[last] = 0;
+					break;
+				}
+			}
+			user_size = strtoll(optarg, (char **)NULL, /*base*/10);
+			user_size <<= shift;
 			if (user_size < 0)
 				errx(1, "Unreasonable volume size: %s", optarg);
 			break;
+		}
 		case 'W':
 			req_flags &= ~(SID_WBus16 | SID_WBus32);
 			switch (atoi(optarg)) {
@@ -163,6 +193,9 @@ main(int argc, char *argv[])
 				/* NOTREACHED */
 			}
 			break;
+		case 'Y':
+			notaio = 1;
+			break;
 		default:
 			usage();
 			/* NOTREACHED */
@@ -200,17 +233,32 @@ main(int argc, char *argv[])
 
 		if (fstat(file_fd, &st) < 0)
 			err(1, "fstat file");
-		volume_size = st.st_size / sector_size;
+#if __FreeBSD_version >= 500000
+		if ((st.st_mode & S_IFCHR) != 0) {
+			/* raw device */
+			off_t mediasize;
+			if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0)
+				err(1, "DIOCGMEDIASIZE"); 
+
+			/* XXX get sector size by ioctl()?? */
+			volume_size = mediasize / sector_size;
+		} else
+#endif
+			volume_size = st.st_size / sector_size;
 	} else {
 		volume_size = user_size / sector_size;
 	}
+	if (debug)
+		warnx("volume_size: %d bytes x " OFF_FMT " sectors",
+		    sector_size, volume_size);
+
 	if (volume_size <= 0)
 		errx(1, "volume must be larger than %d", sector_size);
 
-	{
+	if (notaio == 0) {
 		struct aiocb aio, *aiop;
 		
-		/* Make sure we have working AIO support */
+		/* See if we have we have working AIO support */
 		memset(&aio, 0, sizeof(aio));
 		aio.aio_buf = malloc(sector_size);
 		if (aio.aio_buf == NULL)
@@ -220,16 +268,17 @@ main(int argc, char *argv[])
 		aio.aio_nbytes = sector_size;
 		signal(SIGSYS, SIG_IGN);
 		if (aio_read(&aio) != 0) {
-			printf("You must enable VFS_AIO in your kernel "
-			       "or load the aio(4) module.\n");
-			err(1, "aio_read");
+			printf("AIO support is not available- switchin to"
+			       " single-threaded mode.\n");
+			notaio = 1;
+		} else {
+			if (aio_waitcomplete(&aiop, NULL) != sector_size)
+				err(1, "aio_waitcomplete");
+			assert(aiop == &aio);
+			signal(SIGSYS, SIG_DFL);
 		}
-		if (aio_waitcomplete(&aiop, NULL) != sector_size)
-			err(1, "aio_waitcomplete");
-		assert(aiop == &aio);
-		signal(SIGSYS, SIG_DFL);
 		free((void *)aio.aio_buf);
-		if (debug)
+		if (debug && notaio == 0)
 			warnx("aio support tested ok");
 	}
 
@@ -262,7 +311,7 @@ main(int argc, char *argv[])
 	/* Enable debugging if requested */
 	if (debug) {
 		if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0)
-			err(1, "TARGIOCDEBUG");
+			warnx("TARGIOCDEBUG");
 	}
 
 	/* Set up inquiry data according to what SIM supports */
@@ -372,7 +421,7 @@ request_loop()
 
 	/* Loop until user signal */
 	while (quit == 0) {
-		int retval, i;
+		int retval, i, oo;
 		struct ccb_hdr *ccb_h;
 
 		/* Check for the next signal, read ready, or AIO completion */
@@ -391,7 +440,7 @@ request_loop()
 		}
 
 		/* Process all received events. */
-		for (i = 0; i < retval; i++) {
+		for (oo = i = 0; i < retval; i++) {
 			if ((events[i].flags & EV_ERROR) != 0)
 				errx(1, "kevent registration failed");
 
@@ -415,7 +464,7 @@ request_loop()
 				/* Queue on the appropriate ATIO */
 				queue_io(ctio);
 				/* Process any queued completions. */
-				run_queue(c_descr->atio);
+				oo += run_queue(c_descr->atio);
 				break;
 			}
 			case EVFILT_SIGNAL:
@@ -424,12 +473,17 @@ request_loop()
 				quit = 1;
 				break;
 			default:
-				warnx("unknown event %#x", events[i].filter);
+				warnx("unknown event %d", events[i].filter);
 				break;
 			}
 
 			if (debug)
-				warnx("event done");
+				warnx("event %d done", events[i].filter);
+		}
+
+		if (oo) {
+			tptr = &ts;
+			continue;
 		}
 
 		/* Grab the first CCB and perform one work unit. */
@@ -485,7 +539,7 @@ static void
 handle_read()
 {
 	union ccb *ccb_array[MAX_INITIATORS], *ccb;
-	int ccb_count, i;
+	int ccb_count, i, oo;
 
 	ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array));
 	if (ccb_count <= 0) {
@@ -537,7 +591,7 @@ handle_read()
 			/* Queue on the appropriate ATIO */
 			queue_io(ctio);
 			/* Process any queued completions. */
-			run_queue(c_descr->atio);
+			oo += run_queue(c_descr->atio);
 			break;
 		}
 		case XPT_IMMED_NOTIFY:
@@ -570,8 +624,9 @@ work_atio(struct ccb_accept_tio *atio)
 
 	/* Get a CTIO and initialize it according to our known parameters */
 	ctio = get_ctio();
-	if (ctio == NULL)
+	if (ctio == NULL) {
 		return (1);
+	}
 	ret = 0;
 	ctio->ccb_h.flags = a_descr->flags;
 	ctio->tag_id = atio->tag_id;
@@ -583,6 +638,8 @@ work_atio(struct ccb_accept_tio *atio)
 		c_descr->offset = a_descr->base_off + a_descr->targ_req;
 	else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT)
 		c_descr->offset = a_descr->base_off + a_descr->init_req;
+	else
+		c_descr->offset = a_descr->base_off;
 
 	/* 
 	 * Return a check condition if there was an error while
@@ -608,6 +665,7 @@ work_atio(struct ccb_accept_tio *atio)
 		ret = tcmd_handle(atio, ctio, ATIO_WORK);
 		break;
 	case CAM_REQ_ABORTED:
+		warn("ATIO %p aborted", a_descr);
 		/* Requeue on HBA */
 		TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe);
 		send_ccb((union ccb *)atio, /*priority*/1);
@@ -628,35 +686,29 @@ queue_io(struct ccb_scsiio *ctio)
 {
 	struct ccb_hdr *ccb_h;
 	struct io_queue *ioq;
-	struct ctio_descr *c_descr, *curr_descr;
+	struct ctio_descr *c_descr;
 	
 	c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
-	/* If the completion is for a specific ATIO, queue in order */
-	if (c_descr->atio != NULL) {
-		struct atio_descr *a_descr;
-
-		a_descr = (struct atio_descr *)c_descr->atio->ccb_h.targ_descr;
-		ioq = &a_descr->cmplt_io;
-	} else {
+	if (c_descr->atio == NULL) {
 		errx(1, "CTIO %p has NULL ATIO", ctio);
 	}
+	ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io;
 
-	/* Insert in order, sorted by offset */
-	if (!TAILQ_EMPTY(ioq)) {
-		TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) {
-			curr_descr = (struct ctio_descr *)ccb_h->targ_descr;
-			if (curr_descr->offset <= c_descr->offset) {
-				TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h,
-						   periph_links.tqe);
-				break;
-			}
-			if (TAILQ_PREV(ccb_h, io_queue, periph_links.tqe)
-			    == NULL) {
-				TAILQ_INSERT_BEFORE(ccb_h, &ctio->ccb_h, 
-						    periph_links.tqe);
-				break;
-			}
+	if (TAILQ_EMPTY(ioq)) {
+		TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe);
+		return;
+	}
+
+	TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) {
+		struct ctio_descr *curr_descr = 
+		    (struct ctio_descr *)ccb_h->targ_descr;
+		if (curr_descr->offset <= c_descr->offset) {
+			break;
 		}
+	}
+
+	if (ccb_h) {
+		TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe);
 	} else {
 		TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe);
 	}
@@ -666,7 +718,7 @@ queue_io(struct ccb_scsiio *ctio)
  * Go through all completed AIO/CTIOs for a given ATIO and advance data
  * counts, start continuation IO, etc.
  */
-static void
+static int
 run_queue(struct ccb_accept_tio *atio)
 {
 	struct atio_descr *a_descr;
@@ -674,7 +726,7 @@ run_queue(struct ccb_accept_tio *atio)
 	int sent_status, event;
 
 	if (atio == NULL)
-		return;
+		return (0);
 
 	a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
 
@@ -685,6 +737,14 @@ run_queue(struct ccb_accept_tio *atio)
 		ctio = (struct ccb_scsiio *)ccb_h;
 		c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
 
+		if (ctio->ccb_h.status == CAM_REQ_ABORTED) {
+			TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h,
+				     periph_links.tqe);
+			free_ccb((union ccb *)ctio);
+			send_ccb((union ccb *)atio, /*priority*/1);
+			continue;
+		}
+
 		/* If completed item is in range, call handler */
 		if ((c_descr->event == AIO_DONE &&
 		    c_descr->offset == a_descr->base_off + a_descr->targ_ack)
@@ -702,11 +762,14 @@ run_queue(struct ccb_accept_tio *atio)
 				send_ccb((union ccb *)atio, /*priority*/1);
 		} else {
 			/* Gap in offsets so wait until later callback */
-			if (debug)
-				warnx("IO %p out of order", ccb_h);
-			break;
+			if (/* debug */ 1)
+				warnx("IO %p:%p out of order %s",  ccb_h,
+				    a_descr, c_descr->event == AIO_DONE?
+				    "aio" : "ctio");
+			return (1);
 		}
 	}
+	return (0);
 }
 
 static int
@@ -797,8 +860,10 @@ get_ctio()
 	struct ctio_descr *c_descr;
 	struct sigevent *se;
 
-	if (num_ctios == MAX_CTIOS)
+	if (num_ctios == MAX_CTIOS) {
+		warnx("at CTIO max");
 		return (NULL);
+	}
 
 	ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio));
 	if (ctio == NULL) {
@@ -928,7 +993,7 @@ static void
 usage()
 {
 	fprintf(stderr,
-		"Usage: scsi_target [-AdST] [-b bufsize] [-c sectorsize]\n"
+		"Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n"
 		"\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n"
 		"\t\tbus:target:lun filename\n");
 	exit(1);
diff --git a/share/examples/scsi_target/scsi_target.h b/share/examples/scsi_target/scsi_target.h
index 36bccb9..5a825ee 100644
--- a/share/examples/scsi_target/scsi_target.h
+++ b/share/examples/scsi_target/scsi_target.h
@@ -25,18 +25,17 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/share/examples/scsi_target/scsi_target.h,v 1.1.4.1 2003/02/18 22:07:10 njl Exp $
- * $DragonFly: src/share/examples/scsi_target/scsi_target.h,v 1.2 2003/06/17 04:36:57 dillon Exp $
+ * $FreeBSD$
  */
 
 #ifndef _SCSI_TARGET_H
 #define _SCSI_TARGET_H
 
 /*
- * Maximum number of parallel commands to accept
- * Set to 256 for Fibre Channel (SPI is 16)
+ * Maximum number of parallel commands to accept,
+ * 1024 for Fibre Channel (SPI is 16).
  */
-#define MAX_INITIATORS		16
+#define MAX_INITIATORS		1024
 #define	SECTOR_SIZE		512
 #define MAX_EVENTS		(MAX_INITIATORS + 5)
 				/* kqueue for AIO, signals */
@@ -49,14 +48,57 @@ TAILQ_HEAD(io_queue, ccb_hdr);
 /* Offset into the private CCB area for storing our descriptor */
 #define targ_descr	periph_priv.entries[1].ptr
 
+struct scsi_read_capacity_data_long
+{
+	uint8_t addr[8];
+	uint8_t length[4];
+#define SRC16_PROT_EN	0x01
+#define SRC16_P_TYPE	0x0e
+#define SRC16_PTYPE_1	0x00
+#define SRC16_PTYPE_2	0x02
+#define SRC16_PTYPE_3	0x04
+	uint8_t prot;
+#define SRC16_LBPPBE	0x0f
+#define SRC16_PI_EXPONENT	0xf0
+#define SRC16_PI_EXPONENT_SHIFT	4
+	uint8_t prot_lbppbe;
+#define SRC16_LALBA	0x3f
+#define SRC16_LBPRZ	0x40
+#define SRC16_LBPME	0x80
+/*
+ * Alternate versions of these macros that are intended for use on a 16-bit
+ * version of the lalba_lbp field instead of the array of 2 8 bit numbers.
+ */
+#define SRC16_LALBA_A	0x3fff
+#define SRC16_LBPRZ_A	0x4000
+#define SRC16_LBPME_A	0x8000
+	uint8_t lalba_lbp[2];
+	uint8_t reserved[16];
+};
+
+/*
+struct scsi_report_luns
+{
+	uint8_t opcode;
+	uint8_t reserved1;
+#define RPL_REPORT_DEFAULT	0x00
+#define RPL_REPORT_WELLKNOWN	0x01
+#define RPL_REPORT_ALL		0x02
+	uint8_t select_report;
+	uint8_t reserved2[3];
+	uint8_t length[4];
+	uint8_t reserved3;
+	uint8_t control;
+};
+*/
 /* Descriptor attached to each ATIO */
 struct atio_descr {
 	off_t	  base_off;	/* Base offset for ATIO */
-	size_t	  total_len;	/* Total xfer len for this ATIO */
-	size_t	  init_req;	/* Transfer count requested to/from init */
-	size_t	  init_ack;	/* Data transferred ok to/from init */
-	size_t	  targ_req;	/* Transfer count requested to/from target */
-	size_t	  targ_ack;	/* Data transferred ok to/from target */
+	uint	  total_len;	/* Total xfer len for this ATIO */
+	uint	  init_req;	/* Transfer count requested to/from init */
+	uint	  init_ack;	/* Data transferred ok to/from init */
+	uint	  targ_req;	/* Transfer count requested to/from target */
+	uint	  targ_ack;	/* Data transferred ok to/from target */
 	int	  flags;	/* Flags for CTIOs */
 	u_int8_t *cdb;		/* Pointer to received CDB */
 		  		/* List of completed AIO/CTIOs */
@@ -115,4 +157,16 @@ extern void		send_ccb(union ccb *ccb, int priority);
 extern void		free_ccb(union ccb *ccb);
 static __inline u_int	min(u_int a, u_int b) { return (a < b ? a : b); }
 
+/* Global Data */
+extern int notaio;
+
+/*
+ * Compat Defines
+ */
+#if __FreeBSD_version >= 500000
+#define	OFF_FMT	"%ju"
+#else
+#define	OFF_FMT "%llu"
+#endif
+
 #endif /* _SCSI_TARGET_H */
