Add support for Windows dialect of EXTENDED COPY command, aka Microsoft ODX.

This allows to avoid extra network traffic when copying files on NTFS iSCSI
disks within one storage host by drag'n'dropping them in Windows Explorer
of Windows 8/2012.  It should also accelerate Hyper-V VM operations, etc.

MFC after:	2 weeks
Sponsored by:	iXsystems, Inc.
This commit is contained in:
mav 2014-08-04 01:16:20 +00:00
parent 1d4e2a0972
commit abcceae4d7
7 changed files with 1090 additions and 55 deletions

View File

@ -1023,6 +1023,7 @@ ctl_init(void)
STAILQ_INIT(&softc->port_list);
STAILQ_INIT(&softc->be_list);
STAILQ_INIT(&softc->io_pools);
ctl_tpc_init(softc);
if (ctl_pool_create(softc, CTL_POOL_INTERNAL, CTL_POOL_ENTRIES_INTERNAL,
&internal_pool)!= 0){
@ -1170,6 +1171,7 @@ ctl_shutdown(void)
mtx_destroy(&softc->queue_lock);
#endif
ctl_tpc_shutdown(softc);
mtx_destroy(&softc->pool_lock);
mtx_destroy(&softc->ctl_lock);
@ -4596,7 +4598,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);
ctl_tpc_lun_init(lun);
/*
* Initialize the mode page index.
@ -4748,7 +4750,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);
ctl_tpc_lun_shutdown(lun);
mtx_destroy(&lun->lun_lock);
free(lun->lun_devid, M_CTL);
if (lun->flags & CTL_LUN_MALLOCED)

View File

@ -248,10 +248,18 @@ const struct ctl_cmd_entry ctl_cmd_table_83[32] =
{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},
{ctl_populate_token, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE,
16, { 0x10, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 11 WRITE USING TOKEN */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
{ctl_write_using_token, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE,
16, { 0x11, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 12 */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
@ -334,10 +342,18 @@ const struct ctl_cmd_entry ctl_cmd_table_84[32] =
{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},
{ctl_receive_rod_token_information, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x07, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 08 REPORT ALL ROD TOKENS */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
{ctl_report_all_rod_tokens, CTL_SERIDX_RD_CAP,
CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN,
CTL_LUN_PAT_NONE,
16, {0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
};
/* 9E SERVICE ACTION IN(16) */

View File

@ -422,6 +422,7 @@ struct ctl_thread {
STAILQ_HEAD(, ctl_io_hdr) isc_queue;
};
struct tpc_token;
struct ctl_softc {
struct mtx ctl_lock;
struct cdev *dev;
@ -460,6 +461,8 @@ struct ctl_softc {
time_t last_print_jiffies;
uint32_t skipped_prints;
struct ctl_thread threads[CTL_MAX_THREADS];
TAILQ_HEAD(tpc_tokens, tpc_token) tpc_tokens;
struct callout tpc_timeout;
};
#ifdef _KERNEL
@ -500,8 +503,10 @@ 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);
void ctl_tpc_init(struct ctl_softc *softc);
void ctl_tpc_shutdown(struct ctl_softc *softc);
void ctl_tpc_lun_init(struct ctl_lun *lun);
void ctl_tpc_lun_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);
@ -510,6 +515,10 @@ 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);
int ctl_populate_token(struct ctl_scsiio *ctsio);
int ctl_write_using_token(struct ctl_scsiio *ctsio);
int ctl_receive_rod_token_information(struct ctl_scsiio *ctsio);
int ctl_report_all_rod_tokens(struct ctl_scsiio *ctsio);
#endif /* _KERNEL */

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, pS, pS, bK, bK},
/*RD_CAP */{ pS, pS, pS, pS, pS, pS, bK, pS, pS, pS, pS, bK, pS},
/*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},

File diff suppressed because it is too large Load Diff

View File

@ -5435,32 +5435,37 @@ scsi_devid_is_lun_name(uint8_t *bufp)
}
struct scsi_vpd_id_descriptor *
scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len,
scsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len,
scsi_devid_checkfn_t ck_fn)
{
struct scsi_vpd_id_descriptor *desc;
uint8_t *page_end;
uint8_t *desc_buf_end;
page_end = (uint8_t *)id + page_len;
if (page_end < id->desc_list)
return (NULL);
desc_buf_end = (uint8_t *)desc + len;
desc_buf_end = MIN(id->desc_list + scsi_2btoul(id->length), page_end);
for (desc = (struct scsi_vpd_id_descriptor *)id->desc_list;
desc->identifier <= desc_buf_end
&& desc->identifier + desc->length <= desc_buf_end;
desc = (struct scsi_vpd_id_descriptor *)(desc->identifier
for (; desc->identifier <= desc_buf_end &&
desc->identifier + desc->length <= desc_buf_end;
desc = (struct scsi_vpd_id_descriptor *)(desc->identifier
+ desc->length)) {
if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0)
return (desc);
}
return (NULL);
}
struct scsi_vpd_id_descriptor *
scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len,
scsi_devid_checkfn_t ck_fn)
{
uint32_t len;
if (page_len < sizeof(*id))
return (NULL);
len = MIN(scsi_2btoul(id->length), page_len - sizeof(*id));
return (scsi_get_devid_desc((struct scsi_vpd_id_descriptor *)
id->desc_list, len, ck_fn));
}
int
scsi_transportid_sbuf(struct sbuf *sb, struct scsi_transportid_header *hdr,
uint32_t valid_len)

View File

@ -1351,7 +1351,7 @@ struct scsi_receive_copy_status_lid4_data
uint8_t transfer_count_units;
uint8_t transfer_count[8];
uint8_t segments_processed[2];
uint8_t reserved[2];
uint8_t reserved[6];
uint8_t sense_data[];
};
@ -1533,6 +1533,110 @@ struct scsi_copy_operation_abort
uint8_t control;
};
struct scsi_populate_token
{
uint8_t opcode;
uint8_t service_action;
#define EC_PT 0x10
uint8_t reserved[4];
uint8_t list_identifier[4];
uint8_t length[4];
uint8_t group_number;
uint8_t control;
};
struct scsi_range_desc
{
uint8_t lba[8];
uint8_t length[4];
uint8_t reserved[4];
};
struct scsi_populate_token_data
{
uint8_t length[2];
uint8_t flags;
#define EC_PT_IMMED 0x01
#define EC_PT_RTV 0x02
uint8_t reserved;
uint8_t inactivity_timeout[4];
uint8_t rod_type[4];
uint8_t reserved2[2];
uint8_t range_descriptor_length[2];
struct scsi_range_desc desc[];
};
struct scsi_write_using_token
{
uint8_t opcode;
uint8_t service_action;
#define EC_WUT 0x11
uint8_t reserved[4];
uint8_t list_identifier[4];
uint8_t length[4];
uint8_t group_number;
uint8_t control;
};
struct scsi_write_using_token_data
{
uint8_t length[2];
uint8_t flags;
#define EC_WUT_IMMED 0x01
#define EC_WUT_DEL_TKN 0x02
uint8_t reserved[5];
uint8_t offset_into_rod[8];
uint8_t rod_token[512];
uint8_t reserved2[6];
uint8_t range_descriptor_length[2];
struct scsi_range_desc desc[];
};
struct scsi_receive_rod_token_information
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RRTI 0x07
uint8_t list_identifier[4];
uint8_t reserved[4];
uint8_t length[4];
uint8_t reserved2;
uint8_t control;
};
struct scsi_token
{
uint8_t type[4];
#define ROD_TYPE_INTERNAL 0x00000000
#define ROD_TYPE_AUR 0x00001000
#define ROD_TYPE_PIT_DEF 0x00080000
#define ROD_TYPE_PIT_VULN 0x00080001
#define ROD_TYPE_PIT_PERS 0x00080002
#define ROD_TYPE_PIT_ANY 0x0008FFFF
#define ROD_TYPE_BLOCK_ZERO 0xFFFF0001
uint8_t reserved[2];
uint8_t length[2];
uint8_t body[0];
};
struct scsi_report_all_rod_tokens
{
uint8_t opcode;
uint8_t service_action;
#define RCS_RART 0x08
uint8_t reserved[8];
uint8_t length[4];
uint8_t reserved2;
uint8_t control;
};
struct scsi_report_all_rod_tokens_data
{
uint8_t available_data[4];
uint8_t reserved[4];
uint8_t rod_management_token_list[];
};
struct ata_pass_16 {
u_int8_t opcode;
u_int8_t protocol;
@ -2052,6 +2156,19 @@ struct scsi_vpd_tpc_descriptor
uint8_t parameters[];
};
struct scsi_vpd_tpc_descriptor_bdrl
{
uint8_t desc_type[2];
#define SVPD_TPC_BDRL 0x0000
uint8_t desc_length[2];
uint8_t vendor_specific[6];
uint8_t maximum_ranges[2];
uint8_t maximum_inactivity_timeout[4];
uint8_t default_inactivity_timeout[4];
uint8_t maximum_token_transfer_size[8];
uint8_t optimal_transfer_count[8];
};
struct scsi_vpd_tpc_descriptor_sc_descr
{
uint8_t opcode;
@ -2099,6 +2216,58 @@ struct scsi_vpd_tpc_descriptor_sdid
uint8_t supported_descriptor_ids[];
};
struct scsi_vpd_tpc_descriptor_rtf_block
{
uint8_t type_format;
#define SVPD_TPC_RTF_BLOCK 0x00
uint8_t reserved;
uint8_t desc_length[2];
uint8_t reserved2[2];
uint8_t optimal_length_granularity[2];
uint8_t maximum_bytes[8];
uint8_t optimal_bytes[8];
uint8_t optimal_bytes_to_token_per_segment[8];
uint8_t optimal_bytes_from_token_per_segment[8];
uint8_t reserved3[8];
};
struct scsi_vpd_tpc_descriptor_rtf
{
uint8_t desc_type[2];
#define SVPD_TPC_RTF 0x0106
uint8_t desc_length[2];
uint8_t remote_tokens;
uint8_t reserved[11];
uint8_t minimum_token_lifetime[4];
uint8_t maximum_token_lifetime[4];
uint8_t maximum_token_inactivity_timeout[4];
uint8_t reserved2[18];
uint8_t type_specific_features_length[2];
uint8_t type_specific_features[0];
};
struct scsi_vpd_tpc_descriptor_srtd
{
uint8_t rod_type[4];
uint8_t flags;
#define SVPD_TPC_SRTD_TOUT 0x01
#define SVPD_TPC_SRTD_TIN 0x02
#define SVPD_TPC_SRTD_ECPY 0x80
uint8_t reserved;
uint8_t preference_indicator[2];
uint8_t reserved2[56];
};
struct scsi_vpd_tpc_descriptor_srt
{
uint8_t desc_type[2];
#define SVPD_TPC_SRT 0x0108
uint8_t desc_length[2];
uint8_t reserved[2];
uint8_t rod_type_descriptors_length[2];
uint8_t rod_type_descriptors[0];
};
struct scsi_vpd_tpc_descriptor_gco
{
uint8_t desc_type[2];
@ -3027,6 +3196,9 @@ int scsi_devid_is_lun_t10(uint8_t *bufp);
struct scsi_vpd_id_descriptor *
scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t len,
scsi_devid_checkfn_t ck_fn);
struct scsi_vpd_id_descriptor *
scsi_get_devid_desc(struct scsi_vpd_id_descriptor *desc, uint32_t len,
scsi_devid_checkfn_t ck_fn);
int scsi_transportid_sbuf(struct sbuf *sb,
struct scsi_transportid_header *hdr,