Add support for VMWare dialect of EXTENDED COPY command, aka VAAI Clone.

This allows to clone VMs and move them between LUNs inside one storage
host without generating extra network traffic to the initiator and back,
and without being limited by network bandwidth.

LUNs participating in copy operation should have UNIQUE NAA or EUI IDs set.
For LUNs without these IDs VMWare will use traditional copy operations.

Beware: the above LUN IDs explicitly set to values non-unique from the VM
cluster point of view may cause data corruption if wrong LUN is addressed!

MFC after:	2 weeks
Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2014-07-16 15:57:17 +00:00
parent 22bdc15a57
commit 984a2ea91f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=268767
15 changed files with 2385 additions and 47 deletions

View File

@ -320,10 +320,10 @@ SYSCTL_INT(_kern_cam_ctl, OID_AUTO, verbose, CTLFLAG_RWTUN,
/*
* Supported pages (0x00), Serial number (0x80), Device ID (0x83),
* SCSI Ports (0x88), Block limits (0xB0) and
* SCSI Ports (0x88), Third-party Copy (0x8F), Block limits (0xB0) and
* Logical Block Provisioning (0xB2)
*/
#define SCSI_EVPD_NUM_SUPPORTED_PAGES 6
#define SCSI_EVPD_NUM_SUPPORTED_PAGES 7
static void ctl_isc_event_handler(ctl_ha_channel chanel, ctl_ha_event event,
int param);
@ -349,8 +349,6 @@ static int ctl_ioctl_fill_ooa(struct ctl_lun *lun, uint32_t *cur_fill_num,
struct ctl_ooa_entry *kern_entries);
static int ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td);
uint32_t ctl_get_resindex(struct ctl_nexus *nexus);
uint32_t ctl_port_idx(int port_num);
static uint32_t ctl_map_lun(int port_num, uint32_t lun);
static uint32_t ctl_map_lun_back(int port_num, uint32_t lun);
#ifdef unused
@ -4598,6 +4596,7 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun,
TAILQ_INIT(&lun->ooa_queue);
TAILQ_INIT(&lun->blocked_queue);
STAILQ_INIT(&lun->error_list);
ctl_tpc_init(lun);
/*
* Initialize the mode page index.
@ -4749,6 +4748,7 @@ ctl_free_lun(struct ctl_lun *lun)
atomic_subtract_int(&lun->be_lun->be->num_luns, 1);
lun->be_lun->lun_shutdown(lun->be_lun->be_lun);
ctl_tpc_shutdown(lun);
mtx_destroy(&lun->lun_lock);
free(lun->lun_devid, M_CTL);
if (lun->flags & CTL_LUN_MALLOCED)
@ -9821,10 +9821,12 @@ ctl_inquiry_evpd_supported(struct ctl_scsiio *ctsio, int alloc_len)
pages->page_list[2] = SVPD_DEVICE_ID;
/* SCSI Ports */
pages->page_list[3] = SVPD_SCSI_PORTS;
/* Third-party Copy */
pages->page_list[4] = SVPD_SCSI_TPC;
/* Block limits */
pages->page_list[4] = SVPD_BLOCK_LIMITS;
pages->page_list[5] = SVPD_BLOCK_LIMITS;
/* Logical Block Provisioning */
pages->page_list[5] = SVPD_LBP;
pages->page_list[6] = SVPD_LBP;
ctsio->scsi_status = SCSI_STATUS_OK;
@ -10023,7 +10025,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
struct scsi_vpd_port_designation_cont *pdc;
struct ctl_lun *lun;
struct ctl_port *port;
int data_len, num_target_ports, id_len, g, pg, p;
int data_len, num_target_ports, iid_len, id_len, g, pg, p;
int num_target_port_groups, single;
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
@ -10034,6 +10036,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
else
num_target_port_groups = NUM_TARGET_PORT_GROUPS;
num_target_ports = 0;
iid_len = 0;
id_len = 0;
mtx_lock(&softc->ctl_lock);
STAILQ_FOREACH(port, &softc->port_list, links) {
@ -10043,6 +10046,8 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
CTL_MAX_LUNS)
continue;
num_target_ports++;
if (port->init_devid)
iid_len += port->init_devid->len;
if (port->port_devid)
id_len += port->port_devid->len;
}
@ -10050,7 +10055,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
data_len = sizeof(struct scsi_vpd_scsi_ports) + num_target_port_groups *
num_target_ports * (sizeof(struct scsi_vpd_port_designation) +
sizeof(struct scsi_vpd_port_designation_cont)) + id_len;
sizeof(struct scsi_vpd_port_designation_cont)) + iid_len + id_len;
ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO);
sp = (struct scsi_vpd_scsi_ports *)ctsio->kern_data_ptr;
ctsio->kern_sg_entries = 0;
@ -10098,19 +10103,22 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len)
continue;
p = port->targ_port % CTL_MAX_PORTS + g * CTL_MAX_PORTS;
scsi_ulto2b(p, pd->relative_port_id);
scsi_ulto2b(0, pd->initiator_transportid_length);
if (port->init_devid && g == pg) {
iid_len = port->init_devid->len;
memcpy(pd->initiator_transportid,
port->init_devid->data, port->init_devid->len);
} else
iid_len = 0;
scsi_ulto2b(iid_len, pd->initiator_transportid_length);
pdc = (struct scsi_vpd_port_designation_cont *)
&pd->initiator_transportid[0];
(&pd->initiator_transportid[iid_len]);
if (port->port_devid && g == pg) {
id_len = port->port_devid->len;
scsi_ulto2b(port->port_devid->len,
pdc->target_port_descriptors_length);
memcpy(pdc->target_port_descriptors,
port->port_devid->data, port->port_devid->len);
} else {
} else
id_len = 0;
scsi_ulto2b(0, pdc->target_port_descriptors_length);
}
scsi_ulto2b(id_len, pdc->target_port_descriptors_length);
pd = (struct scsi_vpd_port_designation *)
((uint8_t *)pdc->target_port_descriptors + id_len);
}
@ -10259,6 +10267,9 @@ ctl_inquiry_evpd(struct ctl_scsiio *ctsio)
case SVPD_SCSI_PORTS:
retval = ctl_inquiry_evpd_scsi_ports(ctsio, alloc_len);
break;
case SVPD_SCSI_TPC:
retval = ctl_inquiry_evpd_tpc(ctsio, alloc_len);
break;
case SVPD_BLOCK_LIMITS:
retval = ctl_inquiry_evpd_block_limits(ctsio, alloc_len);
break;
@ -10289,7 +10300,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
struct ctl_lun *lun;
char *val;
uint32_t alloc_len;
int is_fc;
ctl_port_type port_type;
ctl_softc = control_softc;
@ -10298,11 +10309,10 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
* We treat the ioctl front end, and any SCSI adapters, as packetized
* SCSI front ends.
*/
if (ctl_softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]->port_type !=
CTL_PORT_FC)
is_fc = 0;
else
is_fc = 1;
port_type = ctl_softc->ctl_ports[
ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]->port_type;
if (port_type == CTL_PORT_IOCTL || port_type == CTL_PORT_INTERNAL)
port_type = CTL_PORT_SCSI;
lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
cdb = (struct scsi_inquiry *)ctsio->cdb;
@ -10381,7 +10391,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
inq_ptr->device = (SID_QUAL_BAD_LU << 5) | T_NODEVICE;
/* RMB in byte 2 is 0 */
inq_ptr->version = SCSI_REV_SPC3;
inq_ptr->version = SCSI_REV_SPC4;
/*
* According to SAM-3, even if a device only supports a single
@ -10406,17 +10416,18 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
CTL_DEBUG_PRINT(("additional_length = %d\n",
inq_ptr->additional_length));
inq_ptr->spc3_flags = SPC3_SID_TPGS_IMPLICIT;
inq_ptr->spc3_flags = SPC3_SID_3PC;
if (!ctl_is_single)
inq_ptr->spc3_flags |= SPC3_SID_TPGS_IMPLICIT;
/* 16 bit addressing */
if (is_fc == 0)
if (port_type == CTL_PORT_SCSI)
inq_ptr->spc2_flags = SPC2_SID_ADDR16;
/* XXX set the SID_MultiP bit here if we're actually going to
respond on multiple ports */
inq_ptr->spc2_flags |= SPC2_SID_MultiP;
/* 16 bit data bus, synchronous transfers */
/* XXX these flags don't apply for FC */
if (is_fc == 0)
if (port_type == CTL_PORT_SCSI)
inq_ptr->flags = SID_WBus16 | SID_Sync;
/*
* XXX KDM do we want to support tagged queueing on the control
@ -10477,33 +10488,36 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
* and Selection) and Information Unit transfers on both the
* control and array devices.
*/
if (is_fc == 0)
if (port_type == CTL_PORT_SCSI)
inq_ptr->spi3data = SID_SPI_CLOCK_DT_ST | SID_SPI_QAS |
SID_SPI_IUS;
/* SAM-3 */
scsi_ulto2b(0x0060, inq_ptr->version1);
/* SPC-3 (no version claimed) XXX should we claim a version? */
scsi_ulto2b(0x0300, inq_ptr->version2);
if (is_fc) {
/* SAM-5 (no version claimed) */
scsi_ulto2b(0x00A0, inq_ptr->version1);
/* SPC-4 (no version claimed) */
scsi_ulto2b(0x0460, inq_ptr->version2);
if (port_type == CTL_PORT_FC) {
/* FCP-2 ANSI INCITS.350:2003 */
scsi_ulto2b(0x0917, inq_ptr->version3);
} else {
} else if (port_type == CTL_PORT_SCSI) {
/* SPI-4 ANSI INCITS.362:200x */
scsi_ulto2b(0x0B56, inq_ptr->version3);
} else if (port_type == CTL_PORT_ISCSI) {
/* iSCSI (no version claimed) */
scsi_ulto2b(0x0960, inq_ptr->version3);
} else if (port_type == CTL_PORT_SAS) {
/* SAS (no version claimed) */
scsi_ulto2b(0x0BE0, inq_ptr->version3);
}
if (lun == NULL) {
/* SBC-2 (no version claimed) XXX should we claim a version? */
scsi_ulto2b(0x0320, inq_ptr->version4);
/* SBC-3 (no version claimed) */
scsi_ulto2b(0x04C0, inq_ptr->version4);
} else {
switch (lun->be_lun->lun_type) {
case T_DIRECT:
/*
* SBC-2 (no version claimed) XXX should we claim a
* version?
*/
scsi_ulto2b(0x0320, inq_ptr->version4);
/* SBC-3 (no version claimed) */
scsi_ulto2b(0x04C0, inq_ptr->version4);
break;
case T_PROCESSOR:
default:

View File

@ -190,6 +190,156 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] =
/* 08-1f */
};
/* 83 EXTENDED COPY */
const struct ctl_cmd_entry ctl_cmd_table_83[32] =
{
/* 00 EXTENDED COPY (LID1) */
{ctl_extended_copy_lid1, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE,
16, { 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 01 EXTENDED COPY (LID4) */
{ctl_extended_copy_lid4, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE,
16, { 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 02 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 03 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 04 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 05 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 06 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 07 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 08 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 09 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0A */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0B */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0C */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0D */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0E */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 0F */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 10 POPULATE TOKEN */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 11 WRITE USING TOKEN */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 12 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 13 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 14 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 15 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 16 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 17 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 18 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 19 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 1A */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 1B */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 1C COPY OPERATION ABORT */
{ctl_copy_operation_abort, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_NONE,
CTL_LUN_PAT_NONE,
16, { 0x1c, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x07}},
};
/* 84 RECEIVE COPY STATUS */
const struct ctl_cmd_entry ctl_cmd_table_84[32] =
{
/* 00 RECEIVE COPY STATUS (LID1) */
{ctl_receive_copy_status_lid1, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x00, 0xff, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 01 RECEIVE COPY DATA (LID1) */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 02 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 03 RECEIVE COPY OPERATING PARAMETERS */
{ctl_receive_copy_operating_parameters, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_CMD_FLAG_OK_ON_STOPPED |
CTL_CMD_FLAG_OK_ON_INOPERABLE |
CTL_CMD_FLAG_OK_ON_SECONDARY |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 04 RECEIVE COPY FAILURE DETAILS (LID1) */
{ctl_receive_copy_failure_details, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x04, 0xff, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 05 RECEIVE COPY STATUS (LID4) */
{ctl_receive_copy_status_lid4, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x05, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 06 RECEIVE COPY DATA (LID4)*/
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 07 RECEIVE ROD TOKEN INFORMATION */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 08 REPORT ALL ROD TOKENS */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
};
/* 9E SERVICE ACTION IN(16) */
const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
{
@ -844,10 +994,12 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 83 EXTENDED COPY */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
{__DECONST(ctl_opfunc *, ctl_cmd_table_83), CTL_SERIDX_INVLD, CTL_CMD_FLAG_SA5,
CTL_LUN_PAT_NONE},
/* 84 RECEIVE COPY RESULTS */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
{__DECONST(ctl_opfunc *, ctl_cmd_table_84), CTL_SERIDX_INVLD, CTL_CMD_FLAG_SA5,
CTL_LUN_PAT_NONE},
/* 85 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},

View File

@ -234,6 +234,8 @@ ctl_port_deregister(struct ctl_port *port)
port->port_devid = NULL;
free(port->target_devid, M_CTL);
port->target_devid = NULL;
free(port->init_devid, M_CTL);
port->init_devid = NULL;
for (i = 0; i < port->max_initiators; i++)
free(port->wwpn_iid[i].name, M_CTL);
free(port->wwpn_iid, M_CTL);

View File

@ -242,6 +242,7 @@ struct ctl_port {
ctl_options_t options; /* passed to CTL */
struct ctl_devid *port_devid; /* passed to CTL */
struct ctl_devid *target_devid; /* passed to CTL */
struct ctl_devid *init_devid; /* passed to CTL */
STAILQ_ENTRY(ctl_port) fe_links; /* used by CTL */
STAILQ_ENTRY(ctl_port) links; /* used by CTL */
};

View File

@ -2702,7 +2702,7 @@ cfiscsi_scsi_command_done(union ctl_io *io)
* Do not return status for aborted commands.
* There are exceptions, but none supported by CTL yet.
*/
if (io->io_hdr.status == CTL_CMD_ABORTED &&
if ((io->io_hdr.flags & CTL_FLAG_ABORT) &&
(io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) {
ctl_free_io(io);
icl_pdu_free(request);

View File

@ -373,6 +373,7 @@ struct ctl_devid {
*/
#define NUM_TARGET_PORT_GROUPS 2
struct tpc_list;
struct ctl_lun {
struct mtx lun_lock;
struct ctl_id target;
@ -403,6 +404,7 @@ struct ctl_lun {
uint8_t res_type;
uint8_t write_buffer[524288];
struct ctl_devid *lun_devid;
TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;
};
typedef enum {
@ -467,6 +469,8 @@ struct ctl_softc {
extern const struct ctl_cmd_entry ctl_cmd_table[256];
uint32_t ctl_get_initindex(struct ctl_nexus *nexus);
uint32_t ctl_get_resindex(struct ctl_nexus *nexus);
uint32_t ctl_port_idx(int port_num);
int ctl_pool_create(struct ctl_softc *ctl_softc, ctl_pool_type pool_type,
uint32_t total_ctl_io, struct ctl_io_pool **npool);
void ctl_pool_free(struct ctl_io_pool *pool);
@ -498,6 +502,17 @@ int ctl_report_supported_tmf(struct ctl_scsiio *ctsio);
int ctl_report_timestamp(struct ctl_scsiio *ctsio);
int ctl_isc(struct ctl_scsiio *ctsio);
void ctl_tpc_init(struct ctl_lun *lun);
void ctl_tpc_shutdown(struct ctl_lun *lun);
int ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len);
int ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio);
int ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio);
int ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio);
int ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio);
int ctl_extended_copy_lid1(struct ctl_scsiio *ctsio);
int ctl_extended_copy_lid4(struct ctl_scsiio *ctsio);
int ctl_copy_operation_abort(struct ctl_scsiio *ctsio);
#endif /* _KERNEL */
#endif /* _CTL_PRIVATE_H_ */

View File

@ -69,7 +69,7 @@ ctl_serialize_table[CTL_SERIDX_COUNT][CTL_SERIDX_COUNT] = {
/*MD_SEL */{ bK, bK, bK, bK, bK, bK, bK, pS, pS, bK, pS, bK, bK},
/*RQ_SNS */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, bK, pS, bK, bK},
/*INQ */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, pS, pS, bK, bK},
/*RD_CAP */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, bK, pS, bK, bK},
/*RD_CAP */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, pS, pS, bK, bK},
/*RES */{ bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK},
/*LOG_SNS */{ pS, pS, pS, pS, pS, bK, bK, pS, pS, bK, pS, bK, bK},
/*FORMAT */{ pS, bK, bK, bK, bK, bK, pS, pS, bK, bK, bK, bK, bK},

1370
sys/cam/ctl/ctl_tpc.c Normal file

File diff suppressed because it is too large Load Diff

38
sys/cam/ctl/ctl_tpc.h Normal file
View File

@ -0,0 +1,38 @@
/*-
* Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
* 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, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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$
*/
#ifndef _CTL_TPC_H
#define _CTL_TPC_H 1
void tpc_done(union ctl_io *io);
uint64_t tpcl_resolve(int init_port, struct scsi_ec_cscd *cscd, uint32_t *ss);
union ctl_io * tpcl_alloc_io(void);
int tpcl_queue(union ctl_io *io, uint64_t lun);
#endif /* _CTL_TPC_H */

387
sys/cam/ctl/ctl_tpc_local.c Normal file
View File

@ -0,0 +1,387 @@
/*-
* Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
* Copyright (c) 2004, 2005 Silicon Graphics International Corp.
* 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, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/types.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <cam/cam.h>
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_da.h>
#include <cam/ctl/ctl_io.h>
#include <cam/ctl/ctl.h>
#include <cam/ctl/ctl_frontend.h>
#include <cam/ctl/ctl_frontend_internal.h>
#include <cam/ctl/ctl_util.h>
#include <cam/ctl/ctl_backend.h>
#include <cam/ctl/ctl_ioctl.h>
#include <cam/ctl/ctl_ha.h>
#include <cam/ctl/ctl_private.h>
#include <cam/ctl/ctl_debug.h>
#include <cam/ctl/ctl_scsi_all.h>
#include <cam/ctl/ctl_tpc.h>
#include <cam/ctl/ctl_error.h>
struct tpcl_softc {
struct ctl_port port;
int cur_tag_num;
};
extern struct ctl_softc *control_softc;
static struct tpcl_softc tpcl_softc;
static int tpcl_init(void);
static void tpcl_shutdown(void);
static void tpcl_online(void *arg);
static void tpcl_offline(void *arg);
static int tpcl_lun_enable(void *arg, struct ctl_id target_id, int lun_id);
static int tpcl_lun_disable(void *arg, struct ctl_id target_id, int lun_id);
static void tpcl_datamove(union ctl_io *io);
static void tpcl_done(union ctl_io *io);
static struct ctl_frontend tpcl_frontend =
{
.name = "tpc",
.init = tpcl_init,
.shutdown = tpcl_shutdown,
};
CTL_FRONTEND_DECLARE(ctltpc, tpcl_frontend);
static int
tpcl_init(void)
{
struct ctl_softc *softc = control_softc;
struct tpcl_softc *tsoftc = &tpcl_softc;
struct ctl_port *port;
struct scsi_transportid_spi *tid;
int len;
memset(tsoftc, 0, sizeof(*tsoftc));
port = &tsoftc->port;
port->frontend = &tpcl_frontend;
port->port_type = CTL_PORT_INTERNAL;
port->num_requested_ctl_io = 100;
port->port_name = "tpc";
port->port_online = tpcl_online;
port->port_offline = tpcl_offline;
port->onoff_arg = tsoftc;
port->lun_enable = tpcl_lun_enable;
port->lun_disable = tpcl_lun_disable;
port->targ_lun_arg = tsoftc;
port->fe_datamove = tpcl_datamove;
port->fe_done = tpcl_done;
port->max_targets = 1;
port->max_target_id = 0;
port->max_initiators = 1;
if (ctl_port_register(port, (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0)
{
printf("%s: tpc frontend registration failed\n", __func__);
return (0);
}
len = sizeof(struct scsi_transportid_spi);
port->init_devid = malloc(sizeof(struct ctl_devid) + len,
M_CTL, M_WAITOK | M_ZERO);
port->init_devid->len = len;
tid = (struct scsi_transportid_spi *)port->init_devid->data;
tid->format_protocol = SCSI_TRN_SPI_FORMAT_DEFAULT | SCSI_PROTO_SPI;
scsi_ulto2b(0, tid->scsi_addr);
scsi_ulto2b(port->targ_port, tid->rel_trgt_port_id);
ctl_port_online(port);
return (0);
}
void
tpcl_shutdown(void)
{
struct tpcl_softc *tsoftc = &tpcl_softc;
struct ctl_port *port;
port = &tsoftc->port;
ctl_port_offline(port);
if (ctl_port_deregister(&tsoftc->port) != 0)
printf("%s: ctl_frontend_deregister() failed\n", __func__);
}
static void
tpcl_online(void *arg)
{
}
static void
tpcl_offline(void *arg)
{
}
static int
tpcl_lun_enable(void *arg, struct ctl_id target_id, int lun_id)
{
return (0);
}
static int
tpcl_lun_disable(void *arg, struct ctl_id target_id, int lun_id)
{
return (0);
}
static void
tpcl_datamove(union ctl_io *io)
{
struct ctl_sg_entry *ext_sglist, *kern_sglist;
struct ctl_sg_entry ext_entry, kern_entry;
int ext_sg_entries, kern_sg_entries;
int ext_sg_start, ext_offset;
int len_to_copy, len_copied;
int kern_watermark, ext_watermark;
struct ctl_scsiio *ctsio;
int i, j;
ext_sg_start = 0;
ext_offset = 0;
ext_sglist = NULL;
CTL_DEBUG_PRINT(("%s\n", __func__));
ctsio = &io->scsiio;
/*
* If this is the case, we're probably doing a BBR read and don't
* actually need to transfer the data. This will effectively
* bit-bucket the data.
*/
if (ctsio->ext_data_ptr == NULL)
goto bailout;
/*
* To simplify things here, if we have a single buffer, stick it in
* a S/G entry and just make it a single entry S/G list.
*/
if (ctsio->io_hdr.flags & CTL_FLAG_EDPTR_SGLIST) {
int len_seen;
ext_sglist = (struct ctl_sg_entry *)ctsio->ext_data_ptr;
ext_sg_entries = ctsio->ext_sg_entries;
ext_sg_start = 0;
ext_offset = 0;
len_seen = 0;
for (i = 0; i < ext_sg_entries; i++) {
if ((len_seen + ext_sglist[i].len) >=
ctsio->ext_data_filled) {
ext_sg_start = i;
ext_offset = ctsio->ext_data_filled - len_seen;
break;
}
len_seen += ext_sglist[i].len;
}
} else {
ext_sglist = &ext_entry;
ext_sglist->addr = ctsio->ext_data_ptr;
ext_sglist->len = ctsio->ext_data_len;
ext_sg_entries = 1;
ext_sg_start = 0;
ext_offset = ctsio->ext_data_filled;
}
if (ctsio->kern_sg_entries > 0) {
kern_sglist = (struct ctl_sg_entry *)ctsio->kern_data_ptr;
kern_sg_entries = ctsio->kern_sg_entries;
} else {
kern_sglist = &kern_entry;
kern_sglist->addr = ctsio->kern_data_ptr;
kern_sglist->len = ctsio->kern_data_len;
kern_sg_entries = 1;
}
kern_watermark = 0;
ext_watermark = ext_offset;
len_copied = 0;
for (i = ext_sg_start, j = 0;
i < ext_sg_entries && j < kern_sg_entries;) {
uint8_t *ext_ptr, *kern_ptr;
len_to_copy = min(ext_sglist[i].len - ext_watermark,
kern_sglist[j].len - kern_watermark);
ext_ptr = (uint8_t *)ext_sglist[i].addr;
ext_ptr = ext_ptr + ext_watermark;
if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {
/*
* XXX KDM fix this!
*/
panic("need to implement bus address support");
#if 0
kern_ptr = bus_to_virt(kern_sglist[j].addr);
#endif
} else
kern_ptr = (uint8_t *)kern_sglist[j].addr;
kern_ptr = kern_ptr + kern_watermark;
kern_watermark += len_to_copy;
ext_watermark += len_to_copy;
if ((ctsio->io_hdr.flags & CTL_FLAG_DATA_MASK) ==
CTL_FLAG_DATA_IN) {
CTL_DEBUG_PRINT(("%s: copying %d bytes to user\n",
__func__, len_to_copy));
CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
kern_ptr, ext_ptr));
memcpy(ext_ptr, kern_ptr, len_to_copy);
} else {
CTL_DEBUG_PRINT(("%s: copying %d bytes from user\n",
__func__, len_to_copy));
CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
ext_ptr, kern_ptr));
memcpy(kern_ptr, ext_ptr, len_to_copy);
}
len_copied += len_to_copy;
if (ext_sglist[i].len == ext_watermark) {
i++;
ext_watermark = 0;
}
if (kern_sglist[j].len == kern_watermark) {
j++;
kern_watermark = 0;
}
}
ctsio->ext_data_filled += len_copied;
CTL_DEBUG_PRINT(("%s: ext_sg_entries: %d, kern_sg_entries: %d\n",
__func__, ext_sg_entries, kern_sg_entries));
CTL_DEBUG_PRINT(("%s: ext_data_len = %d, kern_data_len = %d\n",
__func__, ctsio->ext_data_len, ctsio->kern_data_len));
/* XXX KDM set residual?? */
bailout:
io->scsiio.be_move_done(io);
}
static void
tpcl_done(union ctl_io *io)
{
tpc_done(io);
}
uint64_t
tpcl_resolve(int init_port, struct scsi_ec_cscd *cscd, uint32_t *ss)
{
struct ctl_softc *softc = control_softc;
struct scsi_ec_cscd_id *cscdid;
struct ctl_port *port;
struct ctl_lun *lun;
uint64_t lunid = UINT64_MAX, l;
int i;
if (cscd->type_code != EC_CSCD_ID)
return (lunid);
cscdid = (struct scsi_ec_cscd_id *)cscd;
mtx_lock(&softc->ctl_lock);
if (init_port >= 0) {
port = softc->ctl_ports[ctl_port_idx(init_port)];
if (port == NULL || port->lun_map == NULL)
init_port = -1;
}
if (init_port < 0) {
STAILQ_FOREACH(lun, &softc->lun_list, links) {
if (lun->lun_devid == NULL)
continue;
if (scsi_devid_match(lun->lun_devid->data,
lun->lun_devid->len, &cscdid->codeset,
cscdid->length + 4) == 0) {
lunid = lun->lun;
if (ss && lun->be_lun)
*ss = lun->be_lun->blocksize;
break;
}
}
} else {
for (i = 0; i < CTL_MAX_LUNS; i++) {
l = port->lun_map(port->targ_lun_arg, i);
if (l >= CTL_MAX_LUNS)
continue;
lun = softc->ctl_luns[l];
if (lun == NULL || lun->lun_devid == NULL)
continue;
if (scsi_devid_match(lun->lun_devid->data,
lun->lun_devid->len, &cscdid->codeset,
cscdid->length + 4) == 0) {
lunid = lun->lun;
if (ss && lun->be_lun)
*ss = lun->be_lun->blocksize;
break;
}
}
}
mtx_unlock(&softc->ctl_lock);
return (lunid);
};
union ctl_io *
tpcl_alloc_io(void)
{
struct tpcl_softc *tsoftc = &tpcl_softc;
return (ctl_alloc_io(tsoftc->port.ctl_pool_ref));
};
int
tpcl_queue(union ctl_io *io, uint64_t lun)
{
struct tpcl_softc *tsoftc = &tpcl_softc;
io->io_hdr.nexus.initid.id = 0;
io->io_hdr.nexus.targ_port = tsoftc->port.targ_port;
io->io_hdr.nexus.targ_target.id = 0;
io->io_hdr.nexus.targ_lun = lun;
io->scsiio.tag_num = atomic_fetchadd_int(&tsoftc->cur_tag_num, 1);
io->scsiio.ext_data_filled = 0;
return (ctl_queue(io));
}

View File

@ -804,8 +804,7 @@ ctlfestart(struct cam_periph *periph, union ccb *start_ccb)
if (io == NULL) {
scsi_status = SCSI_STATUS_BUSY;
csio->sense_len = 0;
} else if ((io->io_hdr.status & CTL_STATUS_MASK) ==
CTL_CMD_ABORTED &&
} else if ((io->io_hdr.flags & CTL_FLAG_ABORT) &&
(io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) {
io->io_hdr.flags &= ~CTL_FLAG_STATUS_QUEUED;

View File

@ -1266,6 +1266,273 @@ struct scsi_report_timestamp_data
uint8_t reserve2[2];
};
struct scsi_receive_copy_status_lid1
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RCS_LID1 0x00
uint8_t list_identifier;
uint8_t reserved[7];
uint8_t length[4];
uint8_t reserved1;
uint8_t control;
};
struct scsi_receive_copy_status_lid1_data
{
uint8_t available_data[4];
uint8_t copy_command_status;
#define RCS_CCS_INPROG 0x00
#define RCS_CCS_COMPLETED 0x01
#define RCS_CCS_ERROR 0x02
uint8_t segments_processed[2];
uint8_t transfer_count_units;
#define RCS_TC_BYTES 0x00
#define RCS_TC_KBYTES 0x01
#define RCS_TC_MBYTES 0x02
#define RCS_TC_GBYTES 0x03
#define RCS_TC_TBYTES 0x04
#define RCS_TC_PBYTES 0x05
#define RCS_TC_EBYTES 0x06
#define RCS_TC_LBAS 0xf1
uint8_t transfer_count[4];
};
struct scsi_receive_copy_failure_details
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RCFD 0x04
uint8_t list_identifier;
uint8_t reserved[7];
uint8_t length[4];
uint8_t reserved1;
uint8_t control;
};
struct scsi_receive_copy_failure_details_data
{
uint8_t available_data[4];
uint8_t reserved[52];
uint8_t copy_command_status;
uint8_t reserved2;
uint8_t sense_data_length[2];
uint8_t sense_data[];
};
struct scsi_receive_copy_status_lid4
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RCS_LID4 0x05
uint8_t list_identifier[4];
uint8_t reserved[4];
uint8_t length[4];
uint8_t reserved1;
uint8_t control;
};
struct scsi_receive_copy_status_lid4_data
{
uint8_t available_data[4];
uint8_t response_to_service_action;
uint8_t copy_command_status;
#define RCS_CCS_COMPLETED_PROD 0x03
#define RCS_CCS_COMPLETED_RESID 0x04
#define RCS_CCS_INPROG_FGBG 0x10
#define RCS_CCS_INPROG_FG 0x11
#define RCS_CCS_INPROG_BG 0x12
#define RCS_CCS_ABORTED 0x60
uint8_t operation_counter[2];
uint8_t estimated_status_update_delay[4];
uint8_t extended_copy_completion_status;
uint8_t length_of_the_sense_data_field;
uint8_t sense_data_length;
uint8_t transfer_count_units;
uint8_t transfer_count[8];
uint8_t segments_processed[2];
uint8_t reserved[2];
uint8_t sense_data[];
};
struct scsi_receive_copy_operating_parameters
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RCOP 0x03
uint8_t reserved[8];
uint8_t length[4];
uint8_t reserved1;
uint8_t control;
};
struct scsi_receive_copy_operating_parameters_data
{
uint8_t length[4];
uint8_t snlid;
#define RCOP_SNLID 0x01
uint8_t reserved[3];
uint8_t maximum_cscd_descriptor_count[2];
uint8_t maximum_segment_descriptor_count[2];
uint8_t maximum_descriptor_list_length[4];
uint8_t maximum_segment_length[4];
uint8_t maximum_inline_data_length[4];
uint8_t held_data_limit[4];
uint8_t maximum_stream_device_transfer_size[4];
uint8_t reserved2[2];
uint8_t total_concurrent_copies[2];
uint8_t maximum_concurrent_copies;
uint8_t data_segment_granularity;
uint8_t inline_data_granularity;
uint8_t held_data_granularity;
uint8_t reserved3[3];
uint8_t implemented_descriptor_list_length;
uint8_t list_of_implemented_descriptor_type_codes[0];
};
struct scsi_extended_copy
{
uint8_t opcode;
uint8_t service_action;
#define EC_EC_LID1 0x00
#define EC_EC_LID4 0x01
uint8_t reserved[8];
uint8_t length[4];
uint8_t reserved1;
uint8_t control;
};
struct scsi_ec_cscd_dtsp
{
uint8_t flags;
#define EC_CSCD_FIXED 0x01
#define EC_CSCD_PAD 0x04
uint8_t block_length[3];
};
struct scsi_ec_cscd
{
uint8_t type_code;
#define EC_CSCD_EXT 0xff
uint8_t luidt_pdt;
#define EC_LUIDT_MASK 0xc0
#define EC_LUIDT_LUN 0x00
#define EC_LUIDT_PROXY_TOKEN 0x40
uint8_t relative_initiator_port[2];
uint8_t cscd_params[24];
struct scsi_ec_cscd_dtsp dtsp;
};
struct scsi_ec_cscd_id
{
uint8_t type_code;
#define EC_CSCD_ID 0xe4
uint8_t luidt_pdt;
uint8_t relative_initiator_port[2];
uint8_t codeset;
uint8_t id_type;
uint8_t reserved;
uint8_t length;
uint8_t designator[20];
struct scsi_ec_cscd_dtsp dtsp;
};
struct scsi_ec_segment
{
uint8_t type_code;
uint8_t flags;
#define EC_SEG_DC 0x02
#define EC_SEG_CAT 0x01
uint8_t descr_length[2];
uint8_t params[];
};
struct scsi_ec_segment_b2b
{
uint8_t type_code;
#define EC_SEG_B2B 0x02
uint8_t flags;
uint8_t descr_length[2];
uint8_t src_cscd[2];
uint8_t dst_cscd[2];
uint8_t reserved[2];
uint8_t number_of_blocks[2];
uint8_t src_lba[8];
uint8_t dst_lba[8];
};
struct scsi_ec_segment_verify
{
uint8_t type_code;
#define EC_SEG_VERIFY 0x07
uint8_t reserved;
uint8_t descr_length[2];
uint8_t src_cscd[2];
uint8_t reserved2[2];
uint8_t tur;
uint8_t reserved3[3];
};
struct scsi_ec_segment_register_key
{
uint8_t type_code;
#define EC_SEG_REGISTER_KEY 0x14
uint8_t reserved;
uint8_t descr_length[2];
uint8_t reserved2[2];
uint8_t dst_cscd[2];
uint8_t res_key[8];
uint8_t sa_res_key[8];
uint8_t reserved3[4];
};
struct scsi_extended_copy_lid1_data
{
uint8_t list_identifier;
uint8_t flags;
#define EC_PRIORITY 0x07
#define EC_LIST_ID_USAGE_MASK 0x18
#define EC_LIST_ID_USAGE_FULL 0x08
#define EC_LIST_ID_USAGE_NOHOLD 0x10
#define EC_LIST_ID_USAGE_NONE 0x18
#define EC_STR 0x20
uint8_t cscd_list_length[2];
uint8_t reserved[4];
uint8_t segment_list_length[4];
uint8_t inline_data_length[4];
uint8_t data[];
};
struct scsi_extended_copy_lid4_data
{
uint8_t list_format;
#define EC_LIST_FORMAT 0x01
uint8_t flags;
uint8_t header_cscd_list_length[2];
uint8_t reserved[11];
uint8_t flags2;
#define EC_IMMED 0x01
#define EC_G_SENSE 0x02
uint8_t header_cscd_type_code;
uint8_t reserved2[3];
uint8_t list_identifier[4];
uint8_t reserved3[18];
uint8_t cscd_list_length[2];
uint8_t segment_list_length[2];
uint8_t inline_data_length[2];
uint8_t data[];
};
struct scsi_copy_operation_abort
{
uint8_t opcode;
uint8_t service_action;
#define EC_COA 0x1c
uint8_t list_identifier[4];
uint8_t reserved[9];
uint8_t control;
};
struct ata_pass_16 {
u_int8_t opcode;
u_int8_t protocol;
@ -1337,6 +1604,8 @@ struct ata_pass_16 {
#define MODE_SENSE_10 0x5A
#define PERSISTENT_RES_IN 0x5E
#define PERSISTENT_RES_OUT 0x5F
#define EXTENDED_COPY 0x83
#define RECEIVE_COPY_STATUS 0x84
#define ATA_PASS_16 0x85
#define READ_16 0x88
#define COMPARE_AND_WRITE 0x89
@ -1450,7 +1719,9 @@ struct scsi_inquiry_data
#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0)
u_int8_t dev_qual2;
#define SID_QUAL2 0x7F
#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
#define SID_LU_CONG 0x40
#define SID_RMB 0x80
#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & SID_RMB) != 0)
u_int8_t version;
#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
#define SCSI_REV_0 0
@ -1773,6 +2044,83 @@ struct scsi_vpd_scsi_ports
*/
#define SVPD_ATA_INFORMATION 0x89
struct scsi_vpd_tpc_descriptor
{
uint8_t desc_type[2];
uint8_t desc_length[2];
uint8_t parameters[];
};
struct scsi_vpd_tpc_descriptor_sc_descr
{
uint8_t opcode;
uint8_t sa_length;
uint8_t supported_service_actions[0];
};
struct scsi_vpd_tpc_descriptor_sc
{
uint8_t desc_type[2];
#define SVPD_TPC_SC 0x0001
uint8_t desc_length[2];
uint8_t list_length;
struct scsi_vpd_tpc_descriptor_sc_descr descr[];
};
struct scsi_vpd_tpc_descriptor_pd
{
uint8_t desc_type[2];
#define SVPD_TPC_PD 0x0004
uint8_t desc_length[2];
uint8_t reserved[4];
uint8_t maximum_cscd_descriptor_count[2];
uint8_t maximum_segment_descriptor_count[2];
uint8_t maximum_descriptor_list_length[4];
uint8_t maximum_inline_data_length[4];
uint8_t reserved2[12];
};
struct scsi_vpd_tpc_descriptor_sd
{
uint8_t desc_type[2];
#define SVPD_TPC_SD 0x0008
uint8_t desc_length[2];
uint8_t list_length;
uint8_t supported_descriptor_codes[];
};
struct scsi_vpd_tpc_descriptor_sdid
{
uint8_t desc_type[2];
#define SVPD_TPC_SDID 0x000C
uint8_t desc_length[2];
uint8_t list_length[2];
uint8_t supported_descriptor_ids[];
};
struct scsi_vpd_tpc_descriptor_gco
{
uint8_t desc_type[2];
#define SVPD_TPC_GCO 0x8001
uint8_t desc_length[2];
uint8_t total_concurrent_copies[4];
uint8_t maximum_identified_concurrent_copies[4];
uint8_t maximum_segment_length[4];
uint8_t data_segment_granularity;
uint8_t inline_data_granularity;
uint8_t reserved[18];
};
struct scsi_vpd_tpc
{
uint8_t device;
uint8_t page_code;
#define SVPD_SCSI_TPC 0x8F
uint8_t page_length[2];
struct scsi_vpd_tpc_descriptor descr[];
};
/*
* Block Device Characteristics VPD Page based on
* T10/1799-D Revision 31

View File

@ -86,6 +86,8 @@ cam/ctl/ctl_frontend_cam_sim.c optional ctl
cam/ctl/ctl_frontend_internal.c optional ctl
cam/ctl/ctl_frontend_iscsi.c optional ctl
cam/ctl/ctl_scsi_all.c optional ctl
cam/ctl/ctl_tpc.c optional ctl
cam/ctl/ctl_tpc_local.c optional ctl
cam/ctl/ctl_error.c optional ctl
cam/ctl/ctl_util.c optional ctl
cam/ctl/scsi_ctl.c optional ctl

View File

@ -14,6 +14,8 @@ SRCS+= ctl_frontend_cam_sim.c
SRCS+= ctl_frontend_internal.c
SRCS+= ctl_frontend_iscsi.c
SRCS+= ctl_scsi_all.c
SRCS+= ctl_tpc.c
SRCS+= ctl_tpc_local.c
SRCS+= ctl_error.c
SRCS+= ctl_util.c
SRCS+= scsi_ctl.c

View File

@ -951,6 +951,14 @@ Specifies LUN SCSI name string.
Specifies LUN EUI-64 identifier.
.It Va naa
Specifies LUN NAA identifier.
Either EUI or NAA identifier should be set to UNIQUE value to allow
EXTENDED COPY command access the LUN.
Non-unique LUN identifiers may lead to data corruption.
.It Va insecure_tpc
Setting to "on" allows EXTENDED COPY command sent to this LUN access
other LUNs on this host, not accessible otherwise.
This allows to offload copying between different iSCSI targets residing
on the same host in trusted environments.
.It Va unmap
Set to "on", enables UNMAP support for the LUN.
.El