summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2010-06-08 22:26:47 +0000
committermjacob <mjacob@FreeBSD.org>2010-06-08 22:26:47 +0000
commitf6ce2bf5e8a87436f3476b2526363cdc1ad5cca4 (patch)
treec03ec9ccda981aafeb69536978756f41f549c6fb /tools
parent78893c5f6359f9f4c01b56c4537ca4671b30702d (diff)
downloadFreeBSD-src-f6ce2bf5e8a87436f3476b2526363cdc1ad5cca4.zip
FreeBSD-src-f6ce2bf5e8a87436f3476b2526363cdc1ad5cca4.tar.gz
Add the VHBA package. It is here in tools because it's really a testbed.
Sponsored by: Panasas MFC after: 1 month
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/vhba/Makefile29
-rw-r--r--tools/tools/vhba/README16
-rw-r--r--tools/tools/vhba/faulty/Makefile7
-rw-r--r--tools/tools/vhba/faulty/vhba_faulty.c349
-rw-r--r--tools/tools/vhba/lots/Makefile7
-rw-r--r--tools/tools/vhba/lots/vhba_lots.c335
-rw-r--r--tools/tools/vhba/medium/Makefile7
-rw-r--r--tools/tools/vhba/medium/vhba_medium.c337
-rw-r--r--tools/tools/vhba/opt_cam.h1
-rw-r--r--tools/tools/vhba/rptluns/Makefile7
-rw-r--r--tools/tools/vhba/rptluns/vhba_rptluns.c366
-rw-r--r--tools/tools/vhba/simple/Makefile7
-rw-r--r--tools/tools/vhba/simple/vhba_simple.c337
-rw-r--r--tools/tools/vhba/vhba.c431
-rw-r--r--tools/tools/vhba/vhba.h116
15 files changed, 2352 insertions, 0 deletions
diff --git a/tools/tools/vhba/Makefile b/tools/tools/vhba/Makefile
new file mode 100644
index 0000000..01e2373
--- /dev/null
+++ b/tools/tools/vhba/Makefile
@@ -0,0 +1,29 @@
+# $FreeBSD$
+#
+# Copyright (c) 2010 by Panasas Inc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice immediately at the beginning of the file, without modification,
+# this list of conditions, and the following disclaimer.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+SUBDIR= simple medium lots faulty rptluns
+
+.include <bsd.subdir.mk>
diff --git a/tools/tools/vhba/README b/tools/tools/vhba/README
new file mode 100644
index 0000000..ced0b5d
--- /dev/null
+++ b/tools/tools/vhba/README
@@ -0,0 +1,16 @@
+$FreeBSD$
+Tue Jun 8 15:02:02 PDT 2010
+
+This packages is a testbed for a number of purposes and consists
+of two pieces.
+
+The first piece is a simple SIM driver for FreeBSD. It provides
+*just enough* framework to be useful, plus some nominally common
+code responses for code sharing purposes.
+
+The second piece(s) are underlying implementations which make various
+virtual devices implemented under the VHBA itself. The current ones
+are pretty much used to stress and test the FreeBSD CAM framework
+itself- this is why this is in the tool directory.
+
+Clearly other connections and possibilities exist as well.
diff --git a/tools/tools/vhba/faulty/Makefile b/tools/tools/vhba/faulty/Makefile
new file mode 100644
index 0000000..bbbb158
--- /dev/null
+++ b/tools/tools/vhba/faulty/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+KMOD= vfaulty
+SRCS= vhba_faulty.c vhba.c
+CFLAGS += -I${.CURDIR}/.. -DVHBA_MOD=\"vfaulty\"
+VPATH= ${.CURDIR}/..
+
+.include <bsd.kmod.mk>
diff --git a/tools/tools/vhba/faulty/vhba_faulty.c b/tools/tools/vhba/faulty/vhba_faulty.c
new file mode 100644
index 0000000..49cbb4b
--- /dev/null
+++ b/tools/tools/vhba/faulty/vhba_faulty.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * "Faulty" Device. Victimize random commands with a Selection Timeout.
+ */
+#include "vhba.h"
+
+#define MAX_TGT VHBA_MAXTGT
+#define MAX_LUN 4
+
+#define DISK_SIZE 32
+#define DISK_SHIFT 9
+#define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
+#define PSEUDO_SPT 64
+#define PSEUDO_HDS 64
+#define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
+
+typedef struct {
+ vhba_softc_t * vhba;
+ uint8_t * disk;
+ size_t disk_size;
+ uint32_t ctr;
+ uint32_t dead;
+ struct task qt;
+} faulty_t;
+
+static void vhba_task(void *, int);
+static void faulty_act(faulty_t *, struct ccb_scsiio *);
+
+void
+vhba_init(vhba_softc_t *vhba)
+{
+ static faulty_t vhbastatic;
+ vhbastatic.vhba = vhba;
+ vhbastatic.disk_size = DISK_SIZE << 20;
+ vhbastatic.disk = malloc(vhbastatic.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
+ vhba->private = &vhbastatic;
+ vhbastatic.ctr = (arc4random() & 0xffff) + 1;
+ TASK_INIT(&vhbastatic.qt, 0, vhba_task, &vhbastatic);
+}
+
+
+void
+vhba_fini(vhba_softc_t *vhba)
+{
+ faulty_t *vhbas = vhba->private;
+ vhba->private = NULL;
+ free(vhbas->disk, M_DEVBUF);
+}
+
+void
+vhba_kick(vhba_softc_t *vhba)
+{
+ faulty_t *vhbas = vhba->private;
+ taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
+}
+
+static void
+vhba_task(void *arg, int pending)
+{
+ faulty_t *vhbas = arg;
+ struct ccb_hdr *ccbh;
+
+ mtx_lock(&vhbas->vhba->lock);
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
+ faulty_act(vhbas, (struct ccb_scsiio *)ccbh);
+ if (--vhbas->ctr == 0) {
+ vhbas->dead = 1;
+ vhbas->ctr = (arc4random() & 0xff) + 1;
+ }
+ }
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
+ xpt_done((union ccb *)ccbh);
+ }
+ mtx_unlock(&vhbas->vhba->lock);
+}
+
+static void
+faulty_act(faulty_t *vhbas, struct ccb_scsiio *csio)
+{
+ char junk[128];
+ cam_status camstatus;
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len;
+ uint64_t off;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ if (csio->ccb_h.target_id >= MAX_TGT) {
+ vhba_set_status(&csio->ccb_h, CAM_SEL_TIMEOUT);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ if (vhbas->dead) {
+ vhbas->dead = 0;
+ vhba_set_status(&csio->ccb_h, CAM_SEL_TIMEOUT);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ if (csio->ccb_h.target_lun >= MAX_LUN && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ {
+ unsigned int nbyte;
+ uint8_t page = cdb[2] & SMS_PAGE_CODE;
+ uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
+
+ switch (page) {
+ case SMS_FORMAT_DEVICE_PAGE:
+ case SMS_GEOMETRY_PAGE:
+ case SMS_CACHE_PAGE:
+ case SMS_CONTROL_MODE_PAGE:
+ case SMS_ALL_PAGES_PAGE:
+ break;
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ memset(junk, 0, sizeof (junk));
+ if (cdb[1] & SMS_DBD) {
+ ptr = &junk[4];
+ } else {
+ ptr = junk;
+ ptr[3] = 8;
+ ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+
+ ptr[8] = (DISK_NBLKS >> 24) & 0xff;
+ ptr[9] = (DISK_NBLKS >> 16) & 0xff;
+ ptr[10] = (DISK_NBLKS >> 8) & 0xff;
+ ptr[11] = DISK_NBLKS & 0xff;
+ ptr += 12;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
+ ptr[0] = SMS_FORMAT_DEVICE_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ /* tracks per zone */
+ /* ptr[2] = 0; */
+ /* ptr[3] = 0; */
+ /* alternate sectors per zone */
+ /* ptr[4] = 0; */
+ /* ptr[5] = 0; */
+ /* alternate tracks per zone */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* alternate tracks per logical unit */
+ /* ptr[8] = 0; */
+ /* ptr[9] = 0; */
+ /* sectors per track */
+ ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
+ ptr[11] = PSEUDO_SPT & 0xff;
+ /* data bytes per physical sector */
+ ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[13] = (1 << DISK_SHIFT) & 0xff;
+ /* interleave */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 1; */
+ /* track skew factor */
+ /* ptr[16] = 0; */
+ /* ptr[17] = 0; */
+ /* cylinder skew factor */
+ /* ptr[18] = 0; */
+ /* ptr[19] = 0; */
+ /* SSRC, HSEC, RMB, SURF */
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
+ ptr[0] = SMS_GEOMETRY_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
+ /* number of cylinders */
+ ptr[2] = (cyl >> 24) & 0xff;
+ ptr[3] = (cyl >> 16) & 0xff;
+ ptr[4] = cyl & 0xff;
+ /* number of heads */
+ ptr[5] = PSEUDO_HDS;
+ /* starting cylinder- write precompensation */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* ptr[8] = 0; */
+ /* starting cylinder- reduced write current */
+ /* ptr[9] = 0; */
+ /* ptr[10] = 0; */
+ /* ptr[11] = 0; */
+ /* drive step rate */
+ /* ptr[12] = 0; */
+ /* ptr[13] = 0; */
+ /* landing zone cylinder */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 0; */
+ /* ptr[16] = 0; */
+ /* RPL */
+ /* ptr[17] = 0; */
+ /* rotational offset */
+ /* ptr[18] = 0; */
+ /* medium rotation rate - 7200 RPM */
+ ptr[20] = 0x1c;
+ ptr[21] = 0x20;
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
+ ptr[0] = SMS_CACHE_PAGE;
+ ptr[1] = 18;
+ ptr[2] = 1 << 2;
+ ptr += 20;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
+ ptr[0] = SMS_CONTROL_MODE_PAGE;
+ ptr[1] = 10;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ ptr[3] = 1 << 4; /* unrestricted reordering allowed */
+ ptr[8] = 0x75; /* 30000 ms */
+ ptr[9] = 0x30;
+ }
+ ptr += 12;
+ }
+ nbyte = (char *)ptr - &junk[0];
+ ptr[0] = nbyte - 4;
+
+ if (cdb[0] == MODE_SENSE) {
+ data_len = min(cdb[4], csio->dxfer_len);
+ } else {
+ uint16_t tw = (cdb[7] << 8) | cdb[8];
+ data_len = min(tw, csio->dxfer_len);
+ }
+ data_len = min(data_len, nbyte);
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ }
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (data_len) {
+ if ((cdb[0] & 0xf) == 8) {
+ memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
+ } else {
+ memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ } else {
+ csio->resid = csio->dxfer_len;
+ }
+ break;
+
+ case READ_CAPACITY:
+ if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
+ vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
+ break;
+ }
+ if (cdb[8] & 0x1) { /* PMI */
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ } else {
+ uint64_t last_blk = DISK_NBLKS - 1;
+ if (last_blk < 0xffffffffULL) {
+ csio->data_ptr[0] = (last_blk >> 24) & 0xff;
+ csio->data_ptr[1] = (last_blk >> 16) & 0xff;
+ csio->data_ptr[2] = (last_blk >> 8) & 0xff;
+ csio->data_ptr[3] = (last_blk) & 0xff;
+ } else {
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ }
+ }
+ csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+ break;
+ default:
+ vhba_default_cmd(csio, MAX_LUN, NULL);
+ break;
+ }
+ if (csio->scsi_status != SCSI_STATUS_OK) {
+ camstatus = CAM_SCSI_STATUS_ERROR;
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ camstatus |= CAM_AUTOSNS_VALID;
+ }
+ } else {
+ csio->scsi_status = SCSI_STATUS_OK;
+ camstatus = CAM_REQ_CMP;
+ }
+ vhba_set_status(&csio->ccb_h, camstatus);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+}
+DEV_MODULE(vhba_faulty, vhba_modprobe, NULL);
diff --git a/tools/tools/vhba/lots/Makefile b/tools/tools/vhba/lots/Makefile
new file mode 100644
index 0000000..37c05c2
--- /dev/null
+++ b/tools/tools/vhba/lots/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+KMOD= vlots
+SRCS= vhba_lots.c vhba.c
+CFLAGS += -I${.CURDIR}/.. -DVHBA_MOD=\"vlots\"
+VPATH= ${.CURDIR}/..
+
+.include <bsd.kmod.mk>
diff --git a/tools/tools/vhba/lots/vhba_lots.c b/tools/tools/vhba/lots/vhba_lots.c
new file mode 100644
index 0000000..0712666
--- /dev/null
+++ b/tools/tools/vhba/lots/vhba_lots.c
@@ -0,0 +1,335 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * VHBA device that just reate boatloads of devices.
+ */
+#include "vhba.h"
+
+#define MAX_TGT VHBA_MAXTGT
+#define MAX_LUN 32
+
+#define DISK_SIZE 32
+#define DISK_SHIFT 9
+#define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
+#define PSEUDO_SPT 64
+#define PSEUDO_HDS 64
+#define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
+
+typedef struct {
+ vhba_softc_t * vhba;
+ uint8_t * disk;
+ size_t disk_size;
+ struct task qt;
+} vhbalots_t;
+
+static void vhba_task(void *, int);
+static void vhbalots_act(vhbalots_t *, struct ccb_scsiio *);
+
+void
+vhba_init(vhba_softc_t *vhba)
+{
+ static vhbalots_t vhbas;
+ vhbas.vhba = vhba;
+ vhbas.disk_size = DISK_SIZE << 20;
+ vhbas.disk = malloc(vhbas.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
+ vhba->private = &vhbas;
+ TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
+}
+
+
+void
+vhba_fini(vhba_softc_t *vhba)
+{
+ vhbalots_t *vhbas = vhba->private;
+ vhba->private = NULL;
+ free(vhbas->disk, M_DEVBUF);
+}
+
+void
+vhba_kick(vhba_softc_t *vhba)
+{
+ vhbalots_t *vhbas = vhba->private;
+ taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
+}
+
+static void
+vhba_task(void *arg, int pending)
+{
+ vhbalots_t *vhbas = arg;
+ struct ccb_hdr *ccbh;
+
+ mtx_lock(&vhbas->vhba->lock);
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
+ vhbalots_act(vhbas, (struct ccb_scsiio *)ccbh);
+ }
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
+ xpt_done((union ccb *)ccbh);
+ }
+ mtx_unlock(&vhbas->vhba->lock);
+}
+
+static void
+vhbalots_act(vhbalots_t *vhbas, struct ccb_scsiio *csio)
+{
+ char junk[128];
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len;
+ uint64_t off;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ if (csio->ccb_h.target_id >= MAX_TGT) {
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ if (csio->ccb_h.target_lun >= MAX_LUN && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ {
+ unsigned int nbyte;
+ uint8_t page = cdb[2] & SMS_PAGE_CODE;
+ uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
+
+ switch (page) {
+ case SMS_FORMAT_DEVICE_PAGE:
+ case SMS_GEOMETRY_PAGE:
+ case SMS_CACHE_PAGE:
+ case SMS_CONTROL_MODE_PAGE:
+ case SMS_ALL_PAGES_PAGE:
+ break;
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ memset(junk, 0, sizeof (junk));
+ if (cdb[1] & SMS_DBD) {
+ ptr = &junk[4];
+ } else {
+ ptr = junk;
+ ptr[3] = 8;
+ ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+
+ ptr[8] = (DISK_NBLKS >> 24) & 0xff;
+ ptr[9] = (DISK_NBLKS >> 16) & 0xff;
+ ptr[10] = (DISK_NBLKS >> 8) & 0xff;
+ ptr[11] = DISK_NBLKS & 0xff;
+ ptr += 12;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
+ ptr[0] = SMS_FORMAT_DEVICE_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ /* tracks per zone */
+ /* ptr[2] = 0; */
+ /* ptr[3] = 0; */
+ /* alternate sectors per zone */
+ /* ptr[4] = 0; */
+ /* ptr[5] = 0; */
+ /* alternate tracks per zone */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* alternate tracks per logical unit */
+ /* ptr[8] = 0; */
+ /* ptr[9] = 0; */
+ /* sectors per track */
+ ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
+ ptr[11] = PSEUDO_SPT & 0xff;
+ /* data bytes per physical sector */
+ ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[13] = (1 << DISK_SHIFT) & 0xff;
+ /* interleave */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 1; */
+ /* track skew factor */
+ /* ptr[16] = 0; */
+ /* ptr[17] = 0; */
+ /* cylinder skew factor */
+ /* ptr[18] = 0; */
+ /* ptr[19] = 0; */
+ /* SSRC, HSEC, RMB, SURF */
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
+ ptr[0] = SMS_GEOMETRY_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
+ /* number of cylinders */
+ ptr[2] = (cyl >> 24) & 0xff;
+ ptr[3] = (cyl >> 16) & 0xff;
+ ptr[4] = cyl & 0xff;
+ /* number of heads */
+ ptr[5] = PSEUDO_HDS;
+ /* starting cylinder- write precompensation */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* ptr[8] = 0; */
+ /* starting cylinder- reduced write current */
+ /* ptr[9] = 0; */
+ /* ptr[10] = 0; */
+ /* ptr[11] = 0; */
+ /* drive step rate */
+ /* ptr[12] = 0; */
+ /* ptr[13] = 0; */
+ /* landing zone cylinder */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 0; */
+ /* ptr[16] = 0; */
+ /* RPL */
+ /* ptr[17] = 0; */
+ /* rotational offset */
+ /* ptr[18] = 0; */
+ /* medium rotation rate - 7200 RPM */
+ ptr[20] = 0x1c;
+ ptr[21] = 0x20;
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
+ ptr[0] = SMS_CACHE_PAGE;
+ ptr[1] = 18;
+ ptr[2] = 1 << 2;
+ ptr += 20;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
+ ptr[0] = SMS_CONTROL_MODE_PAGE;
+ ptr[1] = 10;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ ptr[3] = 1 << 4; /* unrestricted reordering allowed */
+ ptr[8] = 0x75; /* 30000 ms */
+ ptr[9] = 0x30;
+ }
+ ptr += 12;
+ }
+ nbyte = (char *)ptr - &junk[0];
+ ptr[0] = nbyte - 4;
+
+ if (cdb[0] == MODE_SENSE) {
+ data_len = min(cdb[4], csio->dxfer_len);
+ } else {
+ uint16_t tw = (cdb[7] << 8) | cdb[8];
+ data_len = min(tw, csio->dxfer_len);
+ }
+ data_len = min(data_len, nbyte);
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ }
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (data_len) {
+ if ((cdb[0] & 0xf) == 8) {
+ memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
+ } else {
+ memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ } else {
+ csio->resid = csio->dxfer_len;
+ }
+ break;
+
+ case READ_CAPACITY:
+ if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
+ vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
+ break;
+ }
+ if (cdb[8] & 0x1) { /* PMI */
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ } else {
+ uint64_t last_blk = DISK_NBLKS - 1;
+ if (last_blk < 0xffffffffULL) {
+ csio->data_ptr[0] = (last_blk >> 24) & 0xff;
+ csio->data_ptr[1] = (last_blk >> 16) & 0xff;
+ csio->data_ptr[2] = (last_blk >> 8) & 0xff;
+ csio->data_ptr[3] = (last_blk) & 0xff;
+ } else {
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ }
+ }
+ csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+ break;
+ default:
+ vhba_default_cmd(csio, MAX_LUN, NULL);
+ break;
+ }
+ csio->ccb_h.status &= ~CAM_STATUS_MASK;
+ if (csio->scsi_status != SCSI_STATUS_OK) {
+ csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+ } else {
+ csio->scsi_status = SCSI_STATUS_OK;
+ csio->ccb_h.status |= CAM_REQ_CMP;
+ }
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+}
+DEV_MODULE(vhba_lots, vhba_modprobe, NULL);
diff --git a/tools/tools/vhba/medium/Makefile b/tools/tools/vhba/medium/Makefile
new file mode 100644
index 0000000..091e139
--- /dev/null
+++ b/tools/tools/vhba/medium/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+KMOD= vmedium
+SRCS= vhba_medium.c vhba.c
+CFLAGS += -I${.CURDIR}/.. -DVHBA_MOD=\"vmedium\"
+VPATH= ${.CURDIR}/..
+
+.include <bsd.kmod.mk>
diff --git a/tools/tools/vhba/medium/vhba_medium.c b/tools/tools/vhba/medium/vhba_medium.c
new file mode 100644
index 0000000..2fc9f92
--- /dev/null
+++ b/tools/tools/vhba/medium/vhba_medium.c
@@ -0,0 +1,337 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * A VHBA device that has a medium number of device.
+ */
+#include "vhba.h"
+
+#define MAX_TGT 4
+#define MAX_LUN 10
+
+#define DISK_SIZE 32
+#define DISK_SHIFT 9
+#define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
+#define PSEUDO_SPT 64
+#define PSEUDO_HDS 64
+#define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
+
+typedef struct {
+ vhba_softc_t * vhba;
+ uint8_t * disk;
+ size_t disk_size;
+ struct task qt;
+} vhbamedium_t;
+
+static void vhba_task(void *, int);
+static void vhbamedium_act(vhbamedium_t *, struct ccb_scsiio *);
+
+void
+vhba_init(vhba_softc_t *vhba)
+{
+ static vhbamedium_t vhbas;
+ vhbas.vhba = vhba;
+ vhbas.disk_size = DISK_SIZE << 20;
+ vhbas.disk = malloc(vhbas.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
+ vhba->private = &vhbas;
+ TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
+}
+
+
+void
+vhba_fini(vhba_softc_t *vhba)
+{
+ vhbamedium_t *vhbas = vhba->private;
+ vhba->private = NULL;
+ free(vhbas->disk, M_DEVBUF);
+}
+
+void
+vhba_kick(vhba_softc_t *vhba)
+{
+ vhbamedium_t *vhbas = vhba->private;
+ taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
+}
+
+static void
+vhba_task(void *arg, int pending)
+{
+ vhbamedium_t *vhbas = arg;
+ struct ccb_hdr *ccbh;
+
+ mtx_lock(&vhbas->vhba->lock);
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
+ vhbamedium_act(vhbas, (struct ccb_scsiio *)ccbh);
+ }
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
+ xpt_done((union ccb *)ccbh);
+ }
+ mtx_unlock(&vhbas->vhba->lock);
+}
+
+static void
+vhbamedium_act(vhbamedium_t *vhbas, struct ccb_scsiio *csio)
+{
+ char junk[128];
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len;
+ uint64_t off;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ if (csio->ccb_h.target_id >= MAX_TGT) {
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ if (csio->ccb_h.target_lun >= MAX_LUN && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ {
+ unsigned int nbyte;
+ uint8_t page = cdb[2] & SMS_PAGE_CODE;
+ uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
+
+ switch (page) {
+ case SMS_FORMAT_DEVICE_PAGE:
+ case SMS_GEOMETRY_PAGE:
+ case SMS_CACHE_PAGE:
+ case SMS_CONTROL_MODE_PAGE:
+ case SMS_ALL_PAGES_PAGE:
+ break;
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ memset(junk, 0, sizeof (junk));
+ if (cdb[1] & SMS_DBD) {
+ ptr = &junk[4];
+ } else {
+ ptr = junk;
+ ptr[3] = 8;
+ ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+
+ ptr[8] = (DISK_NBLKS >> 24) & 0xff;
+ ptr[9] = (DISK_NBLKS >> 16) & 0xff;
+ ptr[10] = (DISK_NBLKS >> 8) & 0xff;
+ ptr[11] = DISK_NBLKS & 0xff;
+ ptr += 12;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
+ ptr[0] = SMS_FORMAT_DEVICE_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ /* tracks per zone */
+ /* ptr[2] = 0; */
+ /* ptr[3] = 0; */
+ /* alternate sectors per zone */
+ /* ptr[4] = 0; */
+ /* ptr[5] = 0; */
+ /* alternate tracks per zone */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* alternate tracks per logical unit */
+ /* ptr[8] = 0; */
+ /* ptr[9] = 0; */
+ /* sectors per track */
+ ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
+ ptr[11] = PSEUDO_SPT & 0xff;
+ /* data bytes per physical sector */
+ ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[13] = (1 << DISK_SHIFT) & 0xff;
+ /* interleave */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 1; */
+ /* track skew factor */
+ /* ptr[16] = 0; */
+ /* ptr[17] = 0; */
+ /* cylinder skew factor */
+ /* ptr[18] = 0; */
+ /* ptr[19] = 0; */
+ /* SSRC, HSEC, RMB, SURF */
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
+ ptr[0] = SMS_GEOMETRY_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
+ /* number of cylinders */
+ ptr[2] = (cyl >> 24) & 0xff;
+ ptr[3] = (cyl >> 16) & 0xff;
+ ptr[4] = cyl & 0xff;
+ /* number of heads */
+ ptr[5] = PSEUDO_HDS;
+ /* starting cylinder- write precompensation */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* ptr[8] = 0; */
+ /* starting cylinder- reduced write current */
+ /* ptr[9] = 0; */
+ /* ptr[10] = 0; */
+ /* ptr[11] = 0; */
+ /* drive step rate */
+ /* ptr[12] = 0; */
+ /* ptr[13] = 0; */
+ /* landing zone cylinder */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 0; */
+ /* ptr[16] = 0; */
+ /* RPL */
+ /* ptr[17] = 0; */
+ /* rotational offset */
+ /* ptr[18] = 0; */
+ /* medium rotation rate - 7200 RPM */
+ ptr[20] = 0x1c;
+ ptr[21] = 0x20;
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
+ ptr[0] = SMS_CACHE_PAGE;
+ ptr[1] = 18;
+ ptr[2] = 1 << 2;
+ ptr += 20;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
+ ptr[0] = SMS_CONTROL_MODE_PAGE;
+ ptr[1] = 10;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ ptr[3] = 1 << 4; /* unrestricted reordering allowed */
+ ptr[8] = 0x75; /* 30000 ms */
+ ptr[9] = 0x30;
+ }
+ ptr += 12;
+ }
+ nbyte = (char *)ptr - &junk[0];
+ ptr[0] = nbyte - 4;
+
+ if (cdb[0] == MODE_SENSE) {
+ data_len = min(cdb[4], csio->dxfer_len);
+ } else {
+ uint16_t tw = (cdb[7] << 8) | cdb[8];
+ data_len = min(tw, csio->dxfer_len);
+ }
+ data_len = min(data_len, nbyte);
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ }
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (data_len) {
+ if ((cdb[0] & 0xf) == 8) {
+ memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
+ } else {
+ memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ } else {
+ csio->resid = csio->dxfer_len;
+ }
+ break;
+ break;
+
+ case READ_CAPACITY:
+ if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
+ vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
+ break;
+ }
+ if (cdb[8] & 0x1) { /* PMI */
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ } else {
+ uint64_t last_blk = DISK_NBLKS - 1;
+ if (last_blk < 0xffffffffULL) {
+ csio->data_ptr[0] = (last_blk >> 24) & 0xff;
+ csio->data_ptr[1] = (last_blk >> 16) & 0xff;
+ csio->data_ptr[2] = (last_blk >> 8) & 0xff;
+ csio->data_ptr[3] = (last_blk) & 0xff;
+ } else {
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ }
+ }
+ csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+ break;
+
+ default:
+ vhba_default_cmd(csio, MAX_LUN, NULL);
+ break;
+ }
+ csio->ccb_h.status &= ~CAM_STATUS_MASK;
+ if (csio->scsi_status != SCSI_STATUS_OK) {
+ csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+ } else {
+ csio->scsi_status = SCSI_STATUS_OK;
+ csio->ccb_h.status |= CAM_REQ_CMP;
+ }
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+}
+DEV_MODULE(vhba_mediaum, vhba_modprobe, NULL);
diff --git a/tools/tools/vhba/opt_cam.h b/tools/tools/vhba/opt_cam.h
new file mode 100644
index 0000000..da23dbe
--- /dev/null
+++ b/tools/tools/vhba/opt_cam.h
@@ -0,0 +1 @@
+/* $FreeBSD$ */
diff --git a/tools/tools/vhba/rptluns/Makefile b/tools/tools/vhba/rptluns/Makefile
new file mode 100644
index 0000000..a7d81fb
--- /dev/null
+++ b/tools/tools/vhba/rptluns/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+KMOD= vrptluns
+SRCS= vhba_rptluns.c vhba.c
+CFLAGS += -I${.CURDIR}/.. -DVHBA_MOD=\"vrptluns\"
+VPATH= ${.CURDIR}/..
+
+.include <bsd.kmod.mk>
diff --git a/tools/tools/vhba/rptluns/vhba_rptluns.c b/tools/tools/vhba/rptluns/vhba_rptluns.c
new file mode 100644
index 0000000..28424c4
--- /dev/null
+++ b/tools/tools/vhba/rptluns/vhba_rptluns.c
@@ -0,0 +1,366 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * A VHBA device to test REPORT LUN functionality.
+ */
+#include "vhba.h"
+
+#define MAX_TGT 1
+#define MAX_LUN 1024
+
+#define DISK_SIZE 32
+#define DISK_SHIFT 9
+#define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
+#define PSEUDO_SPT 64
+#define PSEUDO_HDS 64
+#define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
+
+typedef struct {
+ vhba_softc_t * vhba;
+ uint8_t * disk;
+ size_t disk_size;
+ struct task qt;
+ uint8_t rpbitmap[MAX_LUN >> 3];
+} vhbarptluns_t;
+
+static void vhba_task(void *, int);
+static void vhbarptluns_act(vhbarptluns_t *, struct ccb_scsiio *);
+
+void
+vhba_init(vhba_softc_t *vhba)
+{
+ static vhbarptluns_t vhbas;
+ struct timeval now;
+ int i;
+
+ vhbas.vhba = vhba;
+ vhbas.disk_size = DISK_SIZE << 20;
+ vhbas.disk = malloc(vhbas.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
+ vhba->private = &vhbas;
+ printf("setting luns");
+ getmicrotime(&now);
+ if (now.tv_usec & 0x1) {
+ vhbas.rpbitmap[0] |= 1;
+ }
+ for (i = 1; i < 8; i++) {
+ if (arc4random() & 1) {
+ printf(" %d", i);
+ vhbas.rpbitmap[0] |= (1 << i);
+ }
+ }
+ for (i = 8; i < MAX_LUN; i++) {
+ if ((arc4random() % i) == 0) {
+ vhbas.rpbitmap[i >> 3] |= (1 << (i & 0x7));
+ printf(" %d", i);
+ }
+ }
+ printf("\n");
+ TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
+}
+
+void
+vhba_fini(vhba_softc_t *vhba)
+{
+ vhbarptluns_t *vhbas = vhba->private;
+ vhba->private = NULL;
+ free(vhbas->disk, M_DEVBUF);
+}
+
+void
+vhba_kick(vhba_softc_t *vhba)
+{
+ vhbarptluns_t *vhbas = vhba->private;
+ taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
+}
+
+static void
+vhba_task(void *arg, int pending)
+{
+ vhbarptluns_t *vhbas = arg;
+ struct ccb_hdr *ccbh;
+
+ mtx_lock(&vhbas->vhba->lock);
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
+ vhbarptluns_act(vhbas, (struct ccb_scsiio *)ccbh);
+ }
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
+ xpt_done((union ccb *)ccbh);
+ }
+ mtx_unlock(&vhbas->vhba->lock);
+}
+
+static void
+vhbarptluns_act(vhbarptluns_t *vhbas, struct ccb_scsiio *csio)
+{
+ char junk[128];
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len;
+ uint64_t off;
+ int i, attached_lun = 0;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ if (csio->ccb_h.target_id >= MAX_TGT) {
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ if (csio->ccb_h.target_lun < MAX_LUN) {
+ i = csio->ccb_h.target_lun & 0x7;
+ if (vhbas->rpbitmap[csio->ccb_h.target_lun >> 3] & (1 << i)) {
+ attached_lun = 1;
+ }
+ }
+ if (attached_lun == 0 && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ {
+ unsigned int nbyte;
+ uint8_t page = cdb[2] & SMS_PAGE_CODE;
+ uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
+
+ switch (page) {
+ case SMS_FORMAT_DEVICE_PAGE:
+ case SMS_GEOMETRY_PAGE:
+ case SMS_CACHE_PAGE:
+ case SMS_CONTROL_MODE_PAGE:
+ case SMS_ALL_PAGES_PAGE:
+ break;
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ memset(junk, 0, sizeof (junk));
+ if (cdb[1] & SMS_DBD) {
+ ptr = &junk[4];
+ } else {
+ ptr = junk;
+ ptr[3] = 8;
+ ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+
+ ptr[8] = (DISK_NBLKS >> 24) & 0xff;
+ ptr[9] = (DISK_NBLKS >> 16) & 0xff;
+ ptr[10] = (DISK_NBLKS >> 8) & 0xff;
+ ptr[11] = DISK_NBLKS & 0xff;
+ ptr += 12;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
+ ptr[0] = SMS_FORMAT_DEVICE_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ /* tracks per zone */
+ /* ptr[2] = 0; */
+ /* ptr[3] = 0; */
+ /* alternate sectors per zone */
+ /* ptr[4] = 0; */
+ /* ptr[5] = 0; */
+ /* alternate tracks per zone */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* alternate tracks per logical unit */
+ /* ptr[8] = 0; */
+ /* ptr[9] = 0; */
+ /* sectors per track */
+ ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
+ ptr[11] = PSEUDO_SPT & 0xff;
+ /* data bytes per physical sector */
+ ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[13] = (1 << DISK_SHIFT) & 0xff;
+ /* interleave */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 1; */
+ /* track skew factor */
+ /* ptr[16] = 0; */
+ /* ptr[17] = 0; */
+ /* cylinder skew factor */
+ /* ptr[18] = 0; */
+ /* ptr[19] = 0; */
+ /* SSRC, HSEC, RMB, SURF */
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
+ ptr[0] = SMS_GEOMETRY_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
+ /* number of cylinders */
+ ptr[2] = (cyl >> 24) & 0xff;
+ ptr[3] = (cyl >> 16) & 0xff;
+ ptr[4] = cyl & 0xff;
+ /* number of heads */
+ ptr[5] = PSEUDO_HDS;
+ /* starting cylinder- write precompensation */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* ptr[8] = 0; */
+ /* starting cylinder- reduced write current */
+ /* ptr[9] = 0; */
+ /* ptr[10] = 0; */
+ /* ptr[11] = 0; */
+ /* drive step rate */
+ /* ptr[12] = 0; */
+ /* ptr[13] = 0; */
+ /* landing zone cylinder */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 0; */
+ /* ptr[16] = 0; */
+ /* RPL */
+ /* ptr[17] = 0; */
+ /* rotational offset */
+ /* ptr[18] = 0; */
+ /* medium rotation rate - 7200 RPM */
+ ptr[20] = 0x1c;
+ ptr[21] = 0x20;
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
+ ptr[0] = SMS_CACHE_PAGE;
+ ptr[1] = 18;
+ ptr[2] = 1 << 2;
+ ptr += 20;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
+ ptr[0] = SMS_CONTROL_MODE_PAGE;
+ ptr[1] = 10;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ ptr[3] = 1 << 4; /* unrestricted reordering allowed */
+ ptr[8] = 0x75; /* 30000 ms */
+ ptr[9] = 0x30;
+ }
+ ptr += 12;
+ }
+ nbyte = (char *)ptr - &junk[0];
+ ptr[0] = nbyte - 4;
+
+ if (cdb[0] == MODE_SENSE) {
+ data_len = min(cdb[4], csio->dxfer_len);
+ } else {
+ uint16_t tw = (cdb[7] << 8) | cdb[8];
+ data_len = min(tw, csio->dxfer_len);
+ }
+ data_len = min(data_len, nbyte);
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ }
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (data_len) {
+ if ((cdb[0] & 0xf) == 8) {
+ memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
+ } else {
+ memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ } else {
+ csio->resid = csio->dxfer_len;
+ }
+ break;
+ break;
+
+ case READ_CAPACITY:
+ if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
+ vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
+ break;
+ }
+ if (cdb[8] & 0x1) { /* PMI */
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ } else {
+ uint64_t last_blk = DISK_NBLKS - 1;
+ if (last_blk < 0xffffffffULL) {
+ csio->data_ptr[0] = (last_blk >> 24) & 0xff;
+ csio->data_ptr[1] = (last_blk >> 16) & 0xff;
+ csio->data_ptr[2] = (last_blk >> 8) & 0xff;
+ csio->data_ptr[3] = (last_blk) & 0xff;
+ } else {
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ }
+ }
+ csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+ break;
+
+ default:
+ vhba_default_cmd(csio, MAX_LUN, vhbas->rpbitmap);
+ break;
+ }
+ csio->ccb_h.status &= ~CAM_STATUS_MASK;
+ if (csio->scsi_status != SCSI_STATUS_OK) {
+ csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+ } else {
+ csio->scsi_status = SCSI_STATUS_OK;
+ csio->ccb_h.status |= CAM_REQ_CMP;
+ }
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+}
+DEV_MODULE(vhba_rtpluns, vhba_modprobe, NULL);
diff --git a/tools/tools/vhba/simple/Makefile b/tools/tools/vhba/simple/Makefile
new file mode 100644
index 0000000..5aa9950
--- /dev/null
+++ b/tools/tools/vhba/simple/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+KMOD= vsimple
+SRCS= vhba_simple.c vhba.c
+CFLAGS += -I${.CURDIR}/.. -DVHBA_MOD=\"vsimple\"
+VPATH= ${.CURDIR}/..
+
+.include <bsd.kmod.mk>
diff --git a/tools/tools/vhba/simple/vhba_simple.c b/tools/tools/vhba/simple/vhba_simple.c
new file mode 100644
index 0000000..bc40bea
--- /dev/null
+++ b/tools/tools/vhba/simple/vhba_simple.c
@@ -0,0 +1,337 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * "Simple" VHBA device
+ */
+#include "vhba.h"
+
+#define MAX_TGT 1
+#define MAX_LUN 1
+
+#define DISK_SIZE 32
+#define DISK_SHIFT 9
+#define DISK_NBLKS ((DISK_SIZE << 20) >> DISK_SHIFT)
+#define PSEUDO_SPT 64
+#define PSEUDO_HDS 64
+#define PSEUDO_SPC (PSEUDO_SPT * PSEUDO_HDS)
+
+typedef struct {
+ vhba_softc_t * vhba;
+ uint8_t * disk;
+ size_t disk_size;
+ struct task qt;
+} vhbasimple_t;
+
+static void vhba_task(void *, int);
+static void vhbasimple_act(vhbasimple_t *, struct ccb_scsiio *);
+
+void
+vhba_init(vhba_softc_t *vhba)
+{
+ static vhbasimple_t vhbas;
+ vhbas.vhba = vhba;
+ vhbas.disk_size = DISK_SIZE << 20;
+ vhbas.disk = malloc(vhbas.disk_size, M_DEVBUF, M_WAITOK|M_ZERO);
+ vhba->private = &vhbas;
+ TASK_INIT(&vhbas.qt, 0, vhba_task, &vhbas);
+}
+
+
+void
+vhba_fini(vhba_softc_t *vhba)
+{
+ vhbasimple_t *vhbas = vhba->private;
+ vhba->private = NULL;
+ free(vhbas->disk, M_DEVBUF);
+}
+
+void
+vhba_kick(vhba_softc_t *vhba)
+{
+ vhbasimple_t *vhbas = vhba->private;
+ taskqueue_enqueue(taskqueue_swi, &vhbas->qt);
+}
+
+static void
+vhba_task(void *arg, int pending)
+{
+ vhbasimple_t *vhbas = arg;
+ struct ccb_hdr *ccbh;
+
+ mtx_lock(&vhbas->vhba->lock);
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->actv)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->actv, ccbh, sim_links.tqe);
+ vhbasimple_act(vhbas, (struct ccb_scsiio *)ccbh);
+ }
+ while ((ccbh = TAILQ_FIRST(&vhbas->vhba->done)) != NULL) {
+ TAILQ_REMOVE(&vhbas->vhba->done, ccbh, sim_links.tqe);
+ xpt_done((union ccb *)ccbh);
+ }
+ mtx_unlock(&vhbas->vhba->lock);
+}
+
+static void
+vhbasimple_act(vhbasimple_t *vhbas, struct ccb_scsiio *csio)
+{
+ char junk[128];
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len;
+ uint64_t off;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ if (csio->ccb_h.target_id >= MAX_TGT) {
+ csio->ccb_h.status = CAM_SEL_TIMEOUT;
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ if (csio->ccb_h.target_lun >= MAX_LUN && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ {
+ unsigned int nbyte;
+ uint8_t page = cdb[2] & SMS_PAGE_CODE;
+ uint8_t pgctl = cdb[2] & SMS_PAGE_CTRL_MASK;
+
+ switch (page) {
+ case SMS_FORMAT_DEVICE_PAGE:
+ case SMS_GEOMETRY_PAGE:
+ case SMS_CACHE_PAGE:
+ case SMS_CONTROL_MODE_PAGE:
+ case SMS_ALL_PAGES_PAGE:
+ break;
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+ return;
+ }
+ memset(junk, 0, sizeof (junk));
+ if (cdb[1] & SMS_DBD) {
+ ptr = &junk[4];
+ } else {
+ ptr = junk;
+ ptr[3] = 8;
+ ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+
+ ptr[8] = (DISK_NBLKS >> 24) & 0xff;
+ ptr[9] = (DISK_NBLKS >> 16) & 0xff;
+ ptr[10] = (DISK_NBLKS >> 8) & 0xff;
+ ptr[11] = DISK_NBLKS & 0xff;
+ ptr += 12;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_FORMAT_DEVICE_PAGE) {
+ ptr[0] = SMS_FORMAT_DEVICE_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ /* tracks per zone */
+ /* ptr[2] = 0; */
+ /* ptr[3] = 0; */
+ /* alternate sectors per zone */
+ /* ptr[4] = 0; */
+ /* ptr[5] = 0; */
+ /* alternate tracks per zone */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* alternate tracks per logical unit */
+ /* ptr[8] = 0; */
+ /* ptr[9] = 0; */
+ /* sectors per track */
+ ptr[10] = (PSEUDO_SPT >> 8) & 0xff;
+ ptr[11] = PSEUDO_SPT & 0xff;
+ /* data bytes per physical sector */
+ ptr[12] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ ptr[13] = (1 << DISK_SHIFT) & 0xff;
+ /* interleave */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 1; */
+ /* track skew factor */
+ /* ptr[16] = 0; */
+ /* ptr[17] = 0; */
+ /* cylinder skew factor */
+ /* ptr[18] = 0; */
+ /* ptr[19] = 0; */
+ /* SSRC, HSEC, RMB, SURF */
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_GEOMETRY_PAGE) {
+ ptr[0] = SMS_GEOMETRY_PAGE;
+ ptr[1] = 24;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ uint32_t cyl = (DISK_NBLKS + ((PSEUDO_SPC - 1))) / PSEUDO_SPC;
+ /* number of cylinders */
+ ptr[2] = (cyl >> 24) & 0xff;
+ ptr[3] = (cyl >> 16) & 0xff;
+ ptr[4] = cyl & 0xff;
+ /* number of heads */
+ ptr[5] = PSEUDO_HDS;
+ /* starting cylinder- write precompensation */
+ /* ptr[6] = 0; */
+ /* ptr[7] = 0; */
+ /* ptr[8] = 0; */
+ /* starting cylinder- reduced write current */
+ /* ptr[9] = 0; */
+ /* ptr[10] = 0; */
+ /* ptr[11] = 0; */
+ /* drive step rate */
+ /* ptr[12] = 0; */
+ /* ptr[13] = 0; */
+ /* landing zone cylinder */
+ /* ptr[14] = 0; */
+ /* ptr[15] = 0; */
+ /* ptr[16] = 0; */
+ /* RPL */
+ /* ptr[17] = 0; */
+ /* rotational offset */
+ /* ptr[18] = 0; */
+ /* medium rotation rate - 7200 RPM */
+ ptr[20] = 0x1c;
+ ptr[21] = 0x20;
+ }
+ ptr += 26;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CACHE_PAGE) {
+ ptr[0] = SMS_CACHE_PAGE;
+ ptr[1] = 18;
+ ptr[2] = 1 << 2;
+ ptr += 20;
+ }
+
+ if (page == SMS_ALL_PAGES_PAGE || page == SMS_CONTROL_MODE_PAGE) {
+ ptr[0] = SMS_CONTROL_MODE_PAGE;
+ ptr[1] = 10;
+ if (pgctl != SMS_PAGE_CTRL_CHANGEABLE) {
+ ptr[3] = 1 << 4; /* unrestricted reordering allowed */
+ ptr[8] = 0x75; /* 30000 ms */
+ ptr[9] = 0x30;
+ }
+ ptr += 12;
+ }
+ nbyte = (char *)ptr - &junk[0];
+ ptr[0] = nbyte - 4;
+
+ if (cdb[0] == MODE_SENSE) {
+ data_len = min(cdb[4], csio->dxfer_len);
+ } else {
+ uint16_t tw = (cdb[7] << 8) | cdb[8];
+ data_len = min(tw, csio->dxfer_len);
+ }
+ data_len = min(data_len, nbyte);
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ }
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ if (vhba_rwparm(cdb, &off, &data_len, DISK_NBLKS, DISK_SHIFT)) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (data_len) {
+ if ((cdb[0] & 0xf) == 8) {
+ memcpy(csio->data_ptr, &vhbas->disk[off], data_len);
+ } else {
+ memcpy(&vhbas->disk[off], csio->data_ptr, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ } else {
+ csio->resid = csio->dxfer_len;
+ }
+ break;
+ break;
+
+ case READ_CAPACITY:
+ if (cdb[2] || cdb[3] || cdb[4] || cdb[5]) {
+ vhba_fill_sense(csio, SSD_KEY_UNIT_ATTENTION, 0x24, 0x0);
+ break;
+ }
+ if (cdb[8] & 0x1) { /* PMI */
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ } else {
+ uint64_t last_blk = DISK_NBLKS - 1;
+ if (last_blk < 0xffffffffULL) {
+ csio->data_ptr[0] = (last_blk >> 24) & 0xff;
+ csio->data_ptr[1] = (last_blk >> 16) & 0xff;
+ csio->data_ptr[2] = (last_blk >> 8) & 0xff;
+ csio->data_ptr[3] = (last_blk) & 0xff;
+ } else {
+ csio->data_ptr[0] = 0xff;
+ csio->data_ptr[1] = 0xff;
+ csio->data_ptr[2] = 0xff;
+ csio->data_ptr[3] = 0xff;
+ }
+ }
+ csio->data_ptr[4] = ((1 << DISK_SHIFT) >> 24) & 0xff;
+ csio->data_ptr[5] = ((1 << DISK_SHIFT) >> 16) & 0xff;
+ csio->data_ptr[6] = ((1 << DISK_SHIFT) >> 8) & 0xff;
+ csio->data_ptr[7] = ((1 << DISK_SHIFT)) & 0xff;
+ break;
+
+ default:
+ vhba_default_cmd(csio, MAX_LUN, NULL);
+ break;
+ }
+ csio->ccb_h.status &= ~CAM_STATUS_MASK;
+ if (csio->scsi_status != SCSI_STATUS_OK) {
+ csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+ } else {
+ csio->scsi_status = SCSI_STATUS_OK;
+ csio->ccb_h.status |= CAM_REQ_CMP;
+ }
+ TAILQ_INSERT_TAIL(&vhbas->vhba->done, &csio->ccb_h, sim_links.tqe);
+}
+DEV_MODULE(vhba_simple, vhba_modprobe, NULL);
diff --git a/tools/tools/vhba/vhba.c b/tools/tools/vhba/vhba.c
new file mode 100644
index 0000000..fd0dce6
--- /dev/null
+++ b/tools/tools/vhba/vhba.c
@@ -0,0 +1,431 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * Virtual HBA infrastructure, to be used for testing as well as other cute hacks.
+ */
+#include "vhba.h"
+static vhba_softc_t *vhba;
+
+#ifndef VHBA_MOD
+#define VHBA_MOD "vhba"
+#endif
+
+static void vhba_action(struct cam_sim *, union ccb *);
+static void vhba_poll(struct cam_sim *);
+
+static int
+vhba_attach(vhba_softc_t *vhba)
+{
+ TAILQ_INIT(&vhba->actv);
+ TAILQ_INIT(&vhba->done);
+ vhba->devq = cam_simq_alloc(VHBA_MAXCMDS);
+ if (vhba->devq == NULL) {
+ return (ENOMEM);
+ }
+ vhba->sim = cam_sim_alloc(vhba_action, vhba_poll, VHBA_MOD, vhba, 0, &vhba->lock, VHBA_MAXCMDS, VHBA_MAXCMDS, vhba->devq);
+ if (vhba->sim == NULL) {
+ cam_simq_free(vhba->devq);
+ return (ENOMEM);
+ }
+ vhba_init(vhba);
+ mtx_lock(&vhba->lock);
+ if (xpt_bus_register(vhba->sim, 0, 0) != CAM_SUCCESS) {
+ cam_sim_free(vhba->sim, TRUE);
+ mtx_unlock(&vhba->lock);
+ return (EIO);
+ }
+ mtx_unlock(&vhba->lock);
+ return (0);
+}
+
+static void
+vhba_detach(vhba_softc_t *vhba)
+{
+ /*
+ * We can't be called with anything queued up.
+ */
+ vhba_fini(vhba);
+ xpt_bus_deregister(cam_sim_path(vhba->sim));
+ cam_sim_free(vhba->sim, TRUE);
+}
+
+static void
+vhba_poll(struct cam_sim *sim)
+{
+ vhba_softc_t *vhba = cam_sim_softc(sim);
+ vhba_kick(vhba);
+}
+
+static void
+vhba_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct ccb_trans_settings *cts;
+ vhba_softc_t *vhba;
+
+ vhba = cam_sim_softc(sim);
+ if (vhba->private == NULL) {
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(ccb);
+ return;
+ }
+ switch (ccb->ccb_h.func_code) {
+ case XPT_SCSI_IO:
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_INPROG;
+ TAILQ_INSERT_TAIL(&vhba->actv, &ccb->ccb_h, sim_links.tqe);
+ vhba_kick(vhba);
+ return;
+
+ case XPT_RESET_DEV:
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+
+ case XPT_GET_TRAN_SETTINGS:
+ cts = &ccb->cts;
+ cts->protocol_version = SCSI_REV_SPC2;
+ cts->protocol = PROTO_SCSI;
+ cts->transport_version = 0;
+ cts->transport = XPORT_PPB;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+
+ case XPT_CALC_GEOMETRY:
+ cam_calc_geometry(&ccb->ccg, 1);
+ break;
+
+ case XPT_RESET_BUS: /* Reset the specified bus */
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+
+ case XPT_PATH_INQ: /* Path routing inquiry */
+ {
+ struct ccb_pathinq *cpi = &ccb->cpi;
+
+ cpi->version_num = 1;
+ cpi->max_target = VHBA_MAXTGT - 1;
+ cpi->max_lun = 16383;
+ cpi->hba_misc = PIM_NOBUSRESET;
+ cpi->initiator_id = cpi->max_target + 1;
+ cpi->transport = XPORT_PPB;
+ cpi->base_transfer_speed = 1000000;
+ cpi->protocol = PROTO_SCSI;
+ cpi->protocol_version = SCSI_REV_SPC2;
+ strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strlcpy(cpi->hba_vid, "FakeHBA", HBA_IDLEN);
+ strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+}
+
+/*
+ * Common support
+ */
+void
+vhba_fill_sense(struct ccb_scsiio *csio, uint8_t key, uint8_t asc, uint8_t ascq)
+{
+ csio->ccb_h.status = CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
+ csio->scsi_status = SCSI_STATUS_CHECK_COND;
+ csio->sense_data.error_code = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
+ csio->sense_data.flags = key;
+ csio->sense_data.extra_len = 10;
+ csio->sense_data.add_sense_code = asc;
+ csio->sense_data.add_sense_code_qual = ascq;
+ csio->sense_len = sizeof (csio->sense_data);
+}
+
+int
+vhba_rwparm(uint8_t *cdb, uint64_t *offset, uint32_t *tl, uint64_t nblks, uint32_t blk_shift)
+{
+ uint32_t cnt;
+ uint64_t lba;
+
+ switch (cdb[0]) {
+ case WRITE_16:
+ case READ_16:
+ cnt = (((uint32_t)cdb[10]) << 24) |
+ (((uint32_t)cdb[11]) << 16) |
+ (((uint32_t)cdb[12]) << 8) |
+ ((uint32_t)cdb[13]);
+
+ lba = (((uint64_t)cdb[2]) << 56) |
+ (((uint64_t)cdb[3]) << 48) |
+ (((uint64_t)cdb[4]) << 40) |
+ (((uint64_t)cdb[5]) << 32) |
+ (((uint64_t)cdb[6]) << 24) |
+ (((uint64_t)cdb[7]) << 16) |
+ (((uint64_t)cdb[8]) << 8) |
+ ((uint64_t)cdb[9]);
+ break;
+ case WRITE_12:
+ case READ_12:
+ cnt = (((uint32_t)cdb[6]) << 16) |
+ (((uint32_t)cdb[7]) << 8) |
+ ((u_int32_t)cdb[8]);
+
+ lba = (((uint32_t)cdb[2]) << 24) |
+ (((uint32_t)cdb[3]) << 16) |
+ (((uint32_t)cdb[4]) << 8) |
+ ((uint32_t)cdb[5]);
+ break;
+ case WRITE_10:
+ case READ_10:
+ cnt = (((uint32_t)cdb[7]) << 8) |
+ ((u_int32_t)cdb[8]);
+
+ lba = (((uint32_t)cdb[2]) << 24) |
+ (((uint32_t)cdb[3]) << 16) |
+ (((uint32_t)cdb[4]) << 8) |
+ ((uint32_t)cdb[5]);
+ break;
+ case WRITE_6:
+ case READ_6:
+ cnt = cdb[4];
+ if (cnt == 0) {
+ cnt = 256;
+ }
+ lba = (((uint32_t)cdb[1] & 0x1f) << 16) |
+ (((uint32_t)cdb[2]) << 8) |
+ ((uint32_t)cdb[3]);
+ break;
+ default:
+ return (-1);
+ }
+
+ if (lba + cnt > nblks) {
+ return (-1);
+ }
+ *tl = cnt << blk_shift;
+ *offset = lba << blk_shift;
+ return (0);
+}
+
+void
+vhba_default_cmd(struct ccb_scsiio *csio, lun_id_t max_lun, uint8_t *sparse_lun_map)
+{
+ char junk[128];
+ const uint8_t niliqd[SHORT_INQUIRY_LENGTH] = {
+ 0x7f, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
+ 'P', 'A', 'N', 'A', 'S', 'A', 'S', ' ',
+ 'N', 'U', 'L', 'L', ' ', 'D', 'E', 'V',
+ 'I', 'C', 'E', ' ', ' ', ' ', ' ', ' ',
+ '0', '0', '0', '1'
+ };
+ const uint8_t iqd[SHORT_INQUIRY_LENGTH] = {
+ 0, 0x0, 0x5, 0x2, 32, 0, 0, 0x32,
+ 'P', 'A', 'N', 'A', 'S', 'A', 'S', ' ',
+ 'V', 'I', 'R', 'T', ' ', 'M', 'E', 'M',
+ 'O', 'R', 'Y', ' ', 'D', 'I', 'S', 'K',
+ '0', '0', '0', '1'
+ };
+ const uint8_t vp0data[6] = { 0, 0, 0, 0x2, 0, 0x80 };
+ const uint8_t vp80data[36] = { 0, 0x80, 0, 0x20 };
+ int i, attached_lun;
+ uint8_t *cdb, *ptr, status;
+ uint32_t data_len, nlun;
+
+ data_len = 0;
+ status = SCSI_STATUS_OK;
+
+ memset(&csio->sense_data, 0, sizeof (csio->sense_data));
+ cdb = csio->cdb_io.cdb_bytes;
+
+ attached_lun = 1;
+ if (csio->ccb_h.target_lun >= max_lun) {
+ attached_lun = 0;
+ } else if (sparse_lun_map) {
+ i = csio->ccb_h.target_lun & 0x7;
+ if ((sparse_lun_map[csio->ccb_h.target_lun >> 3] & (1 << i)) == 0) {
+ attached_lun = 0;
+ }
+ }
+ if (attached_lun == 0 && cdb[0] != INQUIRY && cdb[0] != REPORT_LUNS && cdb[0] != REQUEST_SENSE) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x25, 0x0);
+ return;
+ }
+
+ switch (cdb[0]) {
+ case REQUEST_SENSE:
+ data_len = csio->dxfer_len;
+ if (cdb[4] < csio->dxfer_len)
+ data_len = cdb[4];
+ if (data_len) {
+ memset(junk, 0, sizeof (junk));
+ junk[0] = SSD_ERRCODE_VALID|SSD_CURRENT_ERROR;
+ junk[2] = SSD_KEY_NO_SENSE;
+ junk[7] = 10;
+ memcpy(csio->data_ptr, junk,
+ (data_len > sizeof junk)? sizeof junk : data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ case INQUIRY:
+ i = 0;
+ if ((cdb[1] & 0x1f) == SI_EVPD) {
+ if ((cdb[2] != 0 && cdb[2] != 0x80) || cdb[3] || cdb[5]) {
+ i = 1;
+ }
+ } else if ((cdb[1] & 0x1f) || cdb[2] || cdb[3] || cdb[5]) {
+ i = 1;
+ }
+ if (i) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ if (attached_lun == 0) {
+ if (cdb[1] & 0x1f) {
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x0);
+ break;
+ }
+ memcpy(junk, niliqd, sizeof (niliqd));
+ data_len = sizeof (niliqd);
+ } else if (cdb[1] & 0x1f) {
+ if (cdb[2] == 0) {
+ memcpy(junk, vp0data, sizeof (vp0data));
+ data_len = sizeof (vp0data);
+ } else {
+ memcpy(junk, vp80data, sizeof (vp80data));
+ snprintf(&junk[4], sizeof (vp80data) - 4, "TGT%dLUN%d", csio->ccb_h.target_id, csio->ccb_h.target_lun);
+ for (i = 0; i < sizeof (vp80data); i++) {
+ if (junk[i] == 0) {
+ junk[i] = ' ';
+ }
+ }
+ }
+ data_len = sizeof (vp80data);
+ } else {
+ memcpy(junk, iqd, sizeof (iqd));
+ data_len = sizeof (iqd);
+ }
+ if (data_len > cdb[4]) {
+ data_len = cdb[4];
+ }
+ if (data_len) {
+ memcpy(csio->data_ptr, junk, data_len);
+ }
+ csio->resid = csio->dxfer_len - data_len;
+ break;
+ case TEST_UNIT_READY:
+ case SYNCHRONIZE_CACHE:
+ case START_STOP:
+ case RESERVE:
+ case RELEASE:
+ break;
+
+ case REPORT_LUNS:
+ if (csio->dxfer_len) {
+ memset(csio->data_ptr, 0, csio->dxfer_len);
+ }
+ ptr = NULL;
+ for (nlun = i = 0; i < max_lun; i++) {
+ if (sparse_lun_map) {
+ if ((sparse_lun_map[i >> 3] & (1 << (i & 0x7))) == 0) {
+ continue;
+ }
+ }
+ ptr = &csio->data_ptr[8 + ((nlun++) << 3)];
+ if ((ptr + 8) > &csio->data_ptr[csio->dxfer_len]) {
+ continue;
+ }
+ if (i >= 256) {
+ ptr[0] = 0x40 | ((i >> 8) & 0x3f);
+ }
+ ptr[1] = i;
+ }
+ junk[0] = (nlun << 3) >> 24;
+ junk[1] = (nlun << 3) >> 16;
+ junk[2] = (nlun << 3) >> 8;
+ junk[3] = (nlun << 3);
+ memset(junk+4, 0, 4);
+ if (csio->dxfer_len) {
+ u_int amt;
+
+ amt = MIN(csio->dxfer_len, 8);
+ memcpy(csio->data_ptr, junk, amt);
+ amt = MIN((nlun << 3) + 8, csio->dxfer_len);
+ csio->resid = csio->dxfer_len - amt;
+ }
+ break;
+
+ default:
+ vhba_fill_sense(csio, SSD_KEY_ILLEGAL_REQUEST, 0x20, 0x0);
+ break;
+ }
+}
+
+void
+vhba_set_status(struct ccb_hdr *ccbh, cam_status status)
+{
+ ccbh->status &= ~CAM_STATUS_MASK;
+ ccbh->status |= status;
+ if (status != CAM_REQ_CMP) {
+ if ((ccbh->status & CAM_DEV_QFRZN) == 0) {
+ ccbh->status |= CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccbh->path, 1);
+ }
+ }
+}
+
+int
+vhba_modprobe(module_t mod, int cmd, void *arg)
+{
+ int error = 0;
+
+ switch (cmd) {
+ case MOD_LOAD:
+ vhba = malloc(sizeof (*vhba), M_DEVBUF, M_WAITOK|M_ZERO);
+ mtx_init(&vhba->lock, "vhba", NULL, MTX_DEF);
+ error = vhba_attach(vhba);
+ if (error) {
+ mtx_destroy(&vhba->lock);
+ free(vhba, M_DEVBUF);
+ }
+ break;
+ case MOD_UNLOAD:
+ mtx_lock(&vhba->lock);
+ if (TAILQ_FIRST(&vhba->done) || TAILQ_FIRST(&vhba->actv)) {
+ error = EBUSY;
+ mtx_unlock(&vhba->lock);
+ break;
+ }
+ vhba_detach(vhba);
+ mtx_unlock(&vhba->lock);
+ mtx_destroy(&vhba->lock);
+ free(vhba, M_DEVBUF);
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
diff --git a/tools/tools/vhba/vhba.h b/tools/tools/vhba/vhba.h
new file mode 100644
index 0000000..c09bd00
--- /dev/null
+++ b/tools/tools/vhba/vhba.h
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2010 by Panasas, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+/*
+ * Virtual HBA defines
+ */
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/taskqueue.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/stdarg.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt.h>
+#include <cam/cam_xpt_sim.h>
+#include <cam/cam_debug.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
+
+
+#include <sys/unistd.h>
+#include <sys/kthread.h>
+#include <sys/conf.h>
+#include <sys/module.h>
+#include <sys/ioccom.h>
+#include <sys/devicestat.h>
+#include <cam/cam_periph.h>
+#include <cam/cam_xpt_periph.h>
+
+#define VHBA_MAXTGT 64
+#define VHBA_MAXCMDS 256
+
+typedef struct {
+ struct mtx lock;
+ struct cam_sim * sim;
+ struct cam_devq * devq;
+ TAILQ_HEAD(, ccb_hdr) actv;
+ TAILQ_HEAD(, ccb_hdr) done;
+ void * private;
+} vhba_softc_t;
+
+/*
+ * Each different instantiation of a fake HBA needs to
+ * provide these as function entry points. It's responsible
+ * for setting up some thread or regular timeout that will
+ * dequeue things from the actv queue and put done items
+ * on the done queue.
+ */
+void vhba_init(vhba_softc_t *);
+void vhba_fini(vhba_softc_t *);
+void vhba_kick(vhba_softc_t *);
+
+/*
+ * Support functions
+ */
+void vhba_fill_sense(struct ccb_scsiio *, uint8_t, uint8_t, uint8_t);
+int vhba_rwparm(uint8_t *, uint64_t *, uint32_t *, uint64_t, uint32_t);
+void vhba_default_cmd(struct ccb_scsiio *, lun_id_t, uint8_t *);
+void vhba_set_status(struct ccb_hdr *, cam_status);
+
+/*
+ * Common module loader function
+ */
+int vhba_modprobe(module_t, int, void *);
+
+/*
+ * retrofits
+ */
+#ifndef MODE_SENSE
+#define MODE_SENSE 0x1a
+#endif
+#ifndef SMS_FORMAT_DEVICE_PAGE
+#define SMS_FORMAT_DEVICE_PAGE 0x03
+#endif
+#ifndef SMS_GEOMETRY_PAGE
+#define SMS_GEOMETRY_PAGE 0x04
+#endif
OpenPOWER on IntegriCloud