mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-21 11:13:30 +00:00
Add the VHBA package. It is here in tools because it's really a testbed.
Sponsored by: Panasas MFC after: 1 month
This commit is contained in:
parent
374d9c4d18
commit
8d7b838eee
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208926
29
tools/tools/vhba/Makefile
Normal file
29
tools/tools/vhba/Makefile
Normal file
@ -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>
|
16
tools/tools/vhba/README
Normal file
16
tools/tools/vhba/README
Normal file
@ -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.
|
7
tools/tools/vhba/faulty/Makefile
Normal file
7
tools/tools/vhba/faulty/Makefile
Normal file
@ -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>
|
349
tools/tools/vhba/faulty/vhba_faulty.c
Normal file
349
tools/tools/vhba/faulty/vhba_faulty.c
Normal file
@ -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);
|
7
tools/tools/vhba/lots/Makefile
Normal file
7
tools/tools/vhba/lots/Makefile
Normal file
@ -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>
|
335
tools/tools/vhba/lots/vhba_lots.c
Normal file
335
tools/tools/vhba/lots/vhba_lots.c
Normal file
@ -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);
|
7
tools/tools/vhba/medium/Makefile
Normal file
7
tools/tools/vhba/medium/Makefile
Normal file
@ -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>
|
337
tools/tools/vhba/medium/vhba_medium.c
Normal file
337
tools/tools/vhba/medium/vhba_medium.c
Normal file
@ -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);
|
1
tools/tools/vhba/opt_cam.h
Normal file
1
tools/tools/vhba/opt_cam.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
/* $FreeBSD$ */
|
7
tools/tools/vhba/rptluns/Makefile
Normal file
7
tools/tools/vhba/rptluns/Makefile
Normal file
@ -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>
|
366
tools/tools/vhba/rptluns/vhba_rptluns.c
Normal file
366
tools/tools/vhba/rptluns/vhba_rptluns.c
Normal file
@ -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);
|
7
tools/tools/vhba/simple/Makefile
Normal file
7
tools/tools/vhba/simple/Makefile
Normal file
@ -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>
|
337
tools/tools/vhba/simple/vhba_simple.c
Normal file
337
tools/tools/vhba/simple/vhba_simple.c
Normal file
@ -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);
|
431
tools/tools/vhba/vhba.c
Normal file
431
tools/tools/vhba/vhba.c
Normal file
@ -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);
|
||||||
|
}
|
116
tools/tools/vhba/vhba.h
Normal file
116
tools/tools/vhba/vhba.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user