Add READ BUFFER and improve WRITE BUFFER SCSI commands support.

This gives some use to 512KB per-LUN buffers, allocated for Copan-specific
processor code and not used.  It allows, for example, to test transport
performance and/or correctness without accessing the media, as supported
by Linux version of sg3_utils.

MFC after:	2 weeks
This commit is contained in:
Alexander Motin 2014-06-26 08:56:36 +00:00
parent d8e37c5f72
commit 85165a3f70
4 changed files with 118 additions and 27 deletions

View File

@ -4854,7 +4854,8 @@ ctl_config_move_done(union ctl_io *io)
/*sks_valid*/ 1,
/*retry_count*/
io->io_hdr.port_status);
free(io->scsiio.kern_data_ptr, M_CTL);
if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
free(io->scsiio.kern_data_ptr, M_CTL);
ctl_done(io);
goto bailout;
}
@ -4867,7 +4868,8 @@ ctl_config_move_done(union ctl_io *io)
* S/G list. If we start using S/G lists for config data,
* we'll need to know how to clean them up here as well.
*/
free(io->scsiio.kern_data_ptr, M_CTL);
if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
free(io->scsiio.kern_data_ptr, M_CTL);
/* Hopefully the user has already set the status... */
ctl_done(io);
} else {
@ -5611,24 +5613,106 @@ ctl_format(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
int
ctl_read_buffer(struct ctl_scsiio *ctsio)
{
struct scsi_read_buffer *cdb;
struct ctl_lun *lun;
int buffer_offset, len;
static uint8_t descr[4];
static uint8_t echo_descr[4] = { 0 };
CTL_DEBUG_PRINT(("ctl_read_buffer\n"));
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
cdb = (struct scsi_read_buffer *)ctsio->cdb;
if (lun->flags & CTL_LUN_PR_RESERVED) {
uint32_t residx;
/*
* XXX KDM need a lock here.
*/
residx = ctl_get_resindex(&ctsio->io_hdr.nexus);
if ((lun->res_type == SPR_TYPE_EX_AC
&& residx != lun->pr_res_idx)
|| ((lun->res_type == SPR_TYPE_EX_AC_RO
|| lun->res_type == SPR_TYPE_EX_AC_AR)
&& !lun->per_res[residx].registered)) {
ctl_set_reservation_conflict(ctsio);
ctl_done((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
}
if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA &&
(cdb->byte2 & RWB_MODE) != RWB_MODE_ECHO_DESCR &&
(cdb->byte2 & RWB_MODE) != RWB_MODE_DESCR) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
/*field*/ 1,
/*bit_valid*/ 1,
/*bit*/ 4);
ctl_done((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
if (cdb->buffer_id != 0) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
/*field*/ 2,
/*bit_valid*/ 0,
/*bit*/ 0);
ctl_done((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
len = scsi_3btoul(cdb->length);
buffer_offset = scsi_3btoul(cdb->offset);
if (buffer_offset + len > sizeof(lun->write_buffer)) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
/*field*/ 6,
/*bit_valid*/ 0,
/*bit*/ 0);
ctl_done((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
if ((cdb->byte2 & RWB_MODE) == RWB_MODE_DESCR) {
descr[0] = 0;
scsi_ulto3b(sizeof(lun->write_buffer), &descr[1]);
ctsio->kern_data_ptr = descr;
len = min(len, sizeof(descr));
} else if ((cdb->byte2 & RWB_MODE) == RWB_MODE_ECHO_DESCR) {
ctsio->kern_data_ptr = echo_descr;
len = min(len, sizeof(echo_descr));
} else
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
ctsio->kern_data_len = len;
ctsio->kern_total_len = len;
ctsio->kern_data_resid = 0;
ctsio->kern_rel_offset = 0;
ctsio->kern_sg_entries = 0;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
int
ctl_write_buffer(struct ctl_scsiio *ctsio)
{
struct scsi_write_buffer *cdb;
struct copan_page_header *header;
struct ctl_lun *lun;
struct ctl_softc *ctl_softc;
int buffer_offset, len;
int retval;
header = NULL;
retval = CTL_RETVAL_COMPLETE;
CTL_DEBUG_PRINT(("ctl_write_buffer\n"));
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
ctl_softc = control_softc;
cdb = (struct scsi_write_buffer *)ctsio->cdb;
if ((cdb->byte2 & RWB_MODE) != RWB_MODE_DATA) {
@ -5655,7 +5739,7 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
len = scsi_3btoul(cdb->length);
buffer_offset = scsi_3btoul(cdb->offset);
if (len > sizeof(lun->write_buffer)) {
if (buffer_offset + len > sizeof(lun->write_buffer)) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
@ -5666,23 +5750,12 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
if (buffer_offset != 0) {
ctl_set_invalid_field(ctsio,
/*sks_valid*/ 1,
/*command*/ 1,
/*field*/ 3,
/*bit_valid*/ 0,
/*bit*/ 0);
ctl_done((union ctl_io *)ctsio);
return (CTL_RETVAL_COMPLETE);
}
/*
* If we've got a kernel request that hasn't been malloced yet,
* malloc it and tell the caller the data buffer is here.
*/
if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
ctsio->kern_data_ptr = lun->write_buffer;
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
ctsio->kern_data_len = len;
ctsio->kern_total_len = len;
ctsio->kern_data_resid = 0;
@ -6893,6 +6966,7 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -6952,6 +7026,7 @@ ctl_read_capacity(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -7014,6 +7089,7 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -7184,6 +7260,7 @@ ctl_maintenance_in(struct ctl_scsiio *ctsio)
}
}
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
CTL_DEBUG_PRINT(("buf = %x %x %x %x %x %x %x %x\n",
@ -7409,6 +7486,7 @@ ctl_persistent_reserve_in(struct ctl_scsiio *ctsio)
}
mtx_unlock(&lun->lun_lock);
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
CTL_DEBUG_PRINT(("buf = %x %x %x %x %x %x %x %x\n",
@ -9120,6 +9198,7 @@ ctl_report_luns(struct ctl_scsiio *ctsio)
*/
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9246,7 +9325,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
* parameter data.
*/
ctsio->sense_len = 0;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9275,6 +9354,7 @@ ctl_request_sense(struct ctl_scsiio *ctsio)
* autosense in this case. We're reporting sense as parameter data.
*/
ctsio->sense_len = 0;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9362,6 +9442,7 @@ ctl_inquiry_evpd_supported(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9417,6 +9498,7 @@ ctl_inquiry_evpd_serial(struct ctl_scsiio *ctsio, int alloc_len)
}
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9602,6 +9684,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9658,6 +9741,7 @@ ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len)
scsi_u64to8b(UINT64_MAX, bl_ptr->max_write_same_length);
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9707,6 +9791,7 @@ ctl_inquiry_evpd_lbp(struct ctl_scsiio *ctsio, int alloc_len)
lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 | SVPD_LBP_WS10;
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
@ -9989,6 +10074,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
ctsio->scsi_status = SCSI_STATUS_OK;
if (ctsio->kern_data_len > 0) {
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);
} else {

View File

@ -314,12 +314,15 @@ struct ctl_cmd_entry ctl_cmd_table[] =
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
/* 3B WRITE BUFFER */
{ctl_write_buffer, CTL_SERIDX_WRITE, CTL_CMD_FLAG_OK_ON_PROC |
CTL_FLAG_DATA_OUT,
{ctl_write_buffer, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_OUT,
CTL_LUN_PAT_NONE},
/* 3C READ BUFFER */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
{ctl_read_buffer, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH |
CTL_FLAG_DATA_IN |
CTL_CMD_FLAG_ALLOW_ON_PR_RESV,
CTL_LUN_PAT_NONE},
/* 3D UPDATE BLOCK */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},

View File

@ -2239,6 +2239,7 @@ cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len)
ctsio->scsi_status = SCSI_STATUS_OK;
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
ctsio->be_move_done = ctl_config_move_done;
ctl_datamove((union ctl_io *)ctsio);

View File

@ -476,6 +476,7 @@ int ctl_scsi_reserve(struct ctl_scsiio *ctsio);
int ctl_start_stop(struct ctl_scsiio *ctsio);
int ctl_sync_cache(struct ctl_scsiio *ctsio);
int ctl_format(struct ctl_scsiio *ctsio);
int ctl_read_buffer(struct ctl_scsiio *ctsio);
int ctl_write_buffer(struct ctl_scsiio *ctsio);
int ctl_write_same(struct ctl_scsiio *ctsio);
int ctl_unmap(struct ctl_scsiio *ctsio);